Large diffs are not rendered by default.

@@ -0,0 +1,69 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jboss.as.test.integration.web.access.log;

import java.io.IOException;
import java.io.PrintWriter;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;

/**
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
@WebServlet("simple")
public class SimpleServlet extends HttpServlet {

@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
final PrintWriter writer = response.getWriter();
response.setContentType(MediaType.APPLICATION_JSON);
try (JsonGenerator generator = Json.createGenerator(writer)) {
generator.writeStartObject();

generator.writeStartObject("parameters");

request.getParameterMap().forEach((key, values) -> {
if (values == null) {
generator.writeNull(key);
} else if (values.length > 1) {
generator.writeStartArray(key);
for (String value : values) {
generator.write(value);
}
generator.writeEnd();
} else {
final String value = values[0];
if (value == null) {
generator.writeNull(key);
} else {
generator.write(key, value);
}
}
});

generator.writeEnd(); // end parameters

generator.writeEnd(); // end main
}
}
}
@@ -62,6 +62,10 @@
<groupId>${project.groupId}</groupId>
<artifactId>wildfly-ee</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-event-logger</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-io</artifactId>
@@ -117,6 +121,12 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- Required implementation for the org.wildfly.core:event-logger which is initialized in the subsystem tests -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
@@ -0,0 +1,117 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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 <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
class AccessLogAttribute implements Comparable<AccessLogAttribute> {
private final String key;
private final ExchangeAttribute exchangeAttribute;
private final Function<String, Object> valueConverter;

private AccessLogAttribute(final String key, final ExchangeAttribute exchangeAttribute, final Function<String, Object> 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<String, Object> 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 + "}";
}
}
@@ -36,6 +36,7 @@
public static final String CAPABILITY_HOST_SSO = "org.wildfly.undertow.host.sso";
public static final String CAPABILITY_LOCATION = "org.wildfly.undertow.host.location";
public static final String CAPABILITY_ACCESS_LOG = "org.wildfly.undertow.host.access-log";
public static final String CAPABILITY_CONSOLE_ACCESS_LOG = "org.wildfly.undertow.host.console-access-log";
public static final String CAPABILITY_HANDLER = "org.wildfly.extension.undertow.handler";
public static final String CAPABILITY_MOD_CLUSTER_FILTER = "org.wildfly.undertow.mod_cluster-filter";
public static final String CAPABILITY_SERVLET_CONTAINER = "org.wildfly.undertow.servlet-container";
@@ -0,0 +1,170 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
class ConsoleAccessLogDefinition extends PersistentResourceDefinition {
private static final RuntimeCapability<Void> 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(new ModelNode(true))
.setRestartAllServices()
.build();

static final PropertiesAttributeDefinition METADATA = new PropertiesAttributeDefinition.Builder("metadata", true)
.setAllowExpression(true)
.setRestartAllServices()
.build();

static final Collection<AttributeDefinition> ATTRIBUTES = Arrays.asList(
ExchangeAttributeDefinitions.ATTRIBUTES,
INCLUDE_HOST_NAME,
AccessLogDefinition.WORKER,
AccessLogDefinition.PREDICATE,
METADATA
);
static final ConsoleAccessLogDefinition INSTANCE = new ConsoleAccessLogDefinition();


private ConsoleAccessLogDefinition() {
super(new SimpleResourceDefinition.Parameters(PathElement.pathElement(Constants.SETTING, "console-access-log"),
UndertowExtension.getResolver("console-access-log"))
.setAddHandler(AddHandler.INSTANCE)
.setRemoveHandler(RemoveHandler.INSTANCE)
.addCapabilities(CONSOLE_ACCESS_LOG_CAPABILITY)
);
}

@Override
public Collection<AttributeDefinition> 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<String, Object> 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<Host> hostSupplier = serviceBuilder.requires(
context.getCapabilityServiceName(Capabilities.CAPABILITY_HOST, Host.class, serverName, hostName));
final Supplier<XnioWorker> workerSupplier = serviceBuilder.requires(
context.getCapabilityServiceName(Capabilities.REF_IO_WORKER, XnioWorker.class, worker));

// Get the list of attributes to log
final Collection<AccessLogAttribute> 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<AccessLogAttribute> parseAttributes(final OperationContext context, final ModelNode model) throws OperationFailedException {
final Collection<AccessLogAttribute> 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);
}
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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 <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
class EventLoggerHttpHandler implements HttpHandler {

private final HttpHandler next;
private final ExchangeCompletionListener exchangeCompletionListener = new AccessLogCompletionListener();
private final Predicate predicate;
private final Collection<AccessLogAttribute> 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<AccessLogAttribute> 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<String, Object> data = new LinkedHashMap<>();
for (AccessLogAttribute attribute : attributes) {
data.put(attribute.getKey(), attribute.resolveAttribute(exchange));
}
eventLogger.log(data);
}
} finally {
nextListener.proceed();
}
}
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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 <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
class EventLoggerService implements Service {
private final Set<AccessLogAttribute> attributes;
private final boolean includeHostName;
private final Map<String, Object> metadata;
private final Predicate predicate;
private final Supplier<Host> host;
private final Supplier<XnioWorker> 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<AccessLogAttribute> attributes, final Predicate predicate, final Map<String, Object> metadata,
final boolean includeHostName, final Supplier<Host> host, final Supplier<XnioWorker> 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<HttpHandler, HttpHandler>() {
@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);
}
}

Large diffs are not rendered by default.

@@ -37,6 +37,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Function;
import java.util.regex.Pattern;

import io.undertow.Handlers;
@@ -89,6 +90,8 @@
private final boolean queueRequestsOnStart;
private final int defaultResponseCode;

private volatile Function<HttpHandler, HttpHandler> accessLogHttpHandler;

private final InjectedValue<SuspendController> suspendControllerInjectedValue = new InjectedValue<>();


@@ -158,6 +161,7 @@ public void propertyChange(PropertyChangeEvent evt) {
private HttpHandler configureRootHandler() {
AccessLogService logService = accessLogService;
HttpHandler rootHandler = pathHandler;
final Function<HttpHandler, HttpHandler> accessLogHttpHandler = this.accessLogHttpHandler;

ArrayList<UndertowFilter> filters = new ArrayList<>(this.filters);

@@ -171,6 +175,9 @@ private HttpHandler configureRootHandler() {
if (logService != null) {
rootHandler = logService.configureAccessLogHandler(rootHandler);
}
if (accessLogHttpHandler != null) {
rootHandler = accessLogHttpHandler.apply(rootHandler);
}

// handle .well-known requests from ACME certificate authorities
String path = WildFlySecurityManager.getPropertyPrivileged("jboss.home.dir", ".");
@@ -218,6 +225,11 @@ void setAccessLogService(AccessLogService service) {
rootHandler = null;
}

void setAccessLogHandler(final Function<HttpHandler, HttpHandler> accessLogHttpHandler) {
this.accessLogHttpHandler = accessLogHttpHandler;
rootHandler = null;
}

public Server getServer() {
return server.getValue();
}
@@ -95,6 +95,7 @@
private static final List<? extends PersistentResourceDefinition> CHILDREN = Collections.unmodifiableList(Arrays.asList(
LocationDefinition.INSTANCE,
AccessLogDefinition.INSTANCE,
ConsoleAccessLogDefinition.INSTANCE,
FilterRefDefinition.INSTANCE,
HttpInvokerDefinition.INSTANCE,
new HostSingleSignOnDefinition()
@@ -43,12 +43,13 @@
UNDERTOW_5_0("urn:jboss:domain:undertow:5.0"),
UNDERTOW_6_0("urn:jboss:domain:undertow:6.0"),
UNDERTOW_7_0("urn:jboss:domain:undertow:7.0"),
UNDERTOW_8_0("urn:jboss:domain:undertow:8.0");
UNDERTOW_8_0("urn:jboss:domain:undertow:8.0"),
UNDERTOW_9_0("urn:jboss:domain:undertow:9.0");

/**
* The current namespace version.
*/
public static final Namespace CURRENT = UNDERTOW_8_0;
public static final Namespace CURRENT = UNDERTOW_9_0;

private final String name;

@@ -79,7 +79,7 @@
static final AccessConstraintDefinition LISTENER_CONSTRAINT = new SensitiveTargetAccessConstraintDefinition(
new SensitivityClassification(SUBSYSTEM_NAME, "web-connector", false, false, false));

private static final ModelVersion CURRENT_MODEL_VERSION = ModelVersion.create(8, 0, 0);
private static final ModelVersion CURRENT_MODEL_VERSION = ModelVersion.create(9, 0, 0);


public static StandardResourceDescriptionResolver getResolver(final String... keyPrefix) {
@@ -103,6 +103,7 @@ public void initializeParsers(ExtensionParsingContext context) {
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_6_0.getUriString(), UndertowSubsystemParser_6_0::new);
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_7_0.getUriString(), UndertowSubsystemParser_7_0::new);
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_8_0.getUriString(), UndertowSubsystemParser_8_0::new);
context.setSubsystemXmlMapping(SUBSYSTEM_NAME, Namespace.UNDERTOW_9_0.getUriString(), UndertowSubsystemParser_9_0::new);
}

@Override
@@ -115,7 +116,7 @@ public void initialize(ExtensionContext context) {
deployments.registerSubModel(DeploymentServletDefinition.INSTANCE);
deployments.registerSubModel(DeploymentWebSocketDefinition.INSTANCE);

subsystem.registerXMLElementWriter(UndertowSubsystemParser_8_0::new);
subsystem.registerXMLElementWriter(UndertowSubsystemParser_9_0::new);
}

}

Large diffs are not rendered by default.

@@ -22,9 +22,9 @@

package org.wildfly.extension.undertow;

import static org.wildfly.extension.undertow.ApplicationSecurityDomainDefinition.SECURITY_DOMAIN;
import static org.wildfly.extension.undertow.ApplicationSecurityDomainDefinition.ENABLE_JASPI;
import static org.wildfly.extension.undertow.ApplicationSecurityDomainDefinition.INTEGRATED_JASPI;
import static org.wildfly.extension.undertow.ApplicationSecurityDomainDefinition.SECURITY_DOMAIN;
import static org.wildfly.extension.undertow.Constants.ENABLE_HTTP2;
import static org.wildfly.extension.undertow.HostDefinition.QUEUE_REQUESTS_ON_START;
import static org.wildfly.extension.undertow.HttpListenerResourceDefinition.CERTIFICATE_FORWARDING;
@@ -78,6 +78,7 @@
private static ModelVersion MODEL_VERSION_EAP7_0_0 = ModelVersion.create(3, 1, 0);
private static ModelVersion MODEL_VERSION_EAP7_1_0 = ModelVersion.create(4, 0, 0);
private static ModelVersion MODEL_VERSION_EAP7_2_0 = ModelVersion.create(7, 0, 0);
private static final ModelVersion MODEL_VERSION_WILDFLY_16 = ModelVersion.create(8, 0, 0);

@Override
public String getSubsystemName() {
@@ -89,11 +90,19 @@ public void registerTransformers(SubsystemTransformerRegistration subsystemRegis

ChainedTransformationDescriptionBuilder chainedBuilder = TransformationDescriptionBuilder.Factory.createChainedSubystemInstance(subsystemRegistration.getCurrentSubsystemVersion());

registerTransformers_EAP_7_2_0(chainedBuilder.createBuilder(subsystemRegistration.getCurrentSubsystemVersion(), MODEL_VERSION_EAP7_2_0));
registerTransformersWildFly16(chainedBuilder.createBuilder(subsystemRegistration.getCurrentSubsystemVersion(), MODEL_VERSION_WILDFLY_16));
registerTransformers_EAP_7_2_0(chainedBuilder.createBuilder(MODEL_VERSION_WILDFLY_16, MODEL_VERSION_EAP7_2_0));
registerTransformers_EAP_7_1_0(chainedBuilder.createBuilder(MODEL_VERSION_EAP7_2_0, MODEL_VERSION_EAP7_1_0));
registerTransformers_EAP_7_0_0(chainedBuilder.createBuilder(MODEL_VERSION_EAP7_1_0, MODEL_VERSION_EAP7_0_0));

chainedBuilder.buildAndRegister(subsystemRegistration, new ModelVersion[]{MODEL_VERSION_EAP7_2_0, MODEL_VERSION_EAP7_1_0, MODEL_VERSION_EAP7_0_0});
chainedBuilder.buildAndRegister(subsystemRegistration, new ModelVersion[]{MODEL_VERSION_WILDFLY_16, MODEL_VERSION_EAP7_2_0, MODEL_VERSION_EAP7_1_0, MODEL_VERSION_EAP7_0_0});
}

private static void registerTransformersWildFly16(ResourceTransformationDescriptionBuilder subsystemBuilder) {
subsystemBuilder
.addChildResource(UndertowExtension.SERVER_PATH)
.addChildResource(UndertowExtension.HOST_PATH)
.rejectChildResource(ConsoleAccessLogDefinition.INSTANCE.getPathElement());
}

private static void registerTransformers_EAP_7_2_0(ResourceTransformationDescriptionBuilder subsystemBuilder) {
@@ -410,4 +410,10 @@
@LogMessage(level = WARN)
@Message(id = 101, value = "Duplicate servlet mapping %s found")
void duplicateServletMapping(String mapping);

@Message(id = 102, value = "The pattern %s is not a valid date pattern.")
OperationFailedException invalidDateTimeFormatterPattern(String pattern);

@Message(id = 103, value = "The time zone id %s is invalid.")
OperationFailedException invalidTimeZoneId(String zoneId);
}
@@ -118,6 +118,68 @@ undertow.access-log.use-server-log=If the log should be written to the server lo
undertow.access-log.relative-to=The directory the path is relative to
undertow.access-log.extended=If the log uses the extended log file format
undertow.access-log.predicate=Predicate that determines if the request should be logged
undertow.console-access-log=Allows the access log to be written to the console.
undertow.console-access-log.add=Adds an access logger which writes to the console. The data is written in a JSON format.
undertow.console-access-log.remove=Stops the access logger from writing to the console.
undertow.console-access-log.attributes=The attributes to be included in the structured output.
undertow.console-access-log.attributes.authentication-type=The authentication type used.
undertow.console-access-log.attributes.bytes-sent=The number of bytes, excluding HTTP headers, sent.
undertow.console-access-log.attributes.date-time=The date and time.
undertow.console-access-log.attributes.date-format=The pattern, in the SimpleDateFormatter pattern, used to \
format the date with.
undertow.console-access-log.attributes.time-zone=The time zone used to format the date and/or time assuming the date \
format was defined. This must be a valid java.util.TimeZone.
undertow.console-access-log.attributes.host-and-port=The host and port for the request.
undertow.console-access-log.attributes.local-ip=The IP address of the local connection.
undertow.console-access-log.attributes.local-port=The port of the local connection.
undertow.console-access-log.attributes.local-server-name=The local server name.
undertow.console-access-log.attributes.path-parameter=The name of a parameter in the path. Note that the key for the \
structured output will be the parameter name and the value will be the value of of the parameter.
undertow.console-access-log.attributes.predicate=The name of the predicate context. Note that the key will be the name \
of the predicate and the value will be the resolved from the predicate context.
undertow.console-access-log.attributes.query-parameter=The name of a query parameter. Note that the key for the \
structured output will be the query parameter name.
undertow.console-access-log.attributes.query-string=The query string.
undertow.console-access-log.attributes.include-question-mark=Indicates whether or not the query string should be include the \
question mark.
undertow.console-access-log.attributes.relative-path=The relative path of the request.
undertow.console-access-log.attributes.remote-host=The remote host name.
undertow.console-access-log.attributes.remote-ip=The remote IP address.
undertow.console-access-log.attributes.remote-user=Remote user that was authenticated.
undertow.console-access-log.attributes.request-header=The name of a request header. Note that the key for the \
structured data will be the headers name and the value will be the value of the header.
undertow.console-access-log.attributes.request-line=The request line.
undertow.console-access-log.attributes.request-method=The request method.
undertow.console-access-log.attributes.request-path=The relative path for the request.
undertow.console-access-log.attributes.request-protocol=The protocol for the request.
undertow.console-access-log.attributes.request-scheme=The request URI's scheme.
undertow.console-access-log.attributes.request-url=The original request URI. This will include the host name, protocol \
etc. if it was specified by the client.
undertow.console-access-log.attributes.resolved-path=The resolved path.
undertow.console-access-log.attributes.response-code=The response code.
undertow.console-access-log.attributes.response-header=The name of the response header. Note the key for the \
structured data will be the header name and the value will be the value of the header.
undertow.console-access-log.attributes.response-reason-phrase=The text reason for the response code.
undertow.console-access-log.attributes.response-time=The time used to process the request.
undertow.console-access-log.attributes.time-unit=The unit of time used for the response time.
undertow.console-access-log.attributes.secure-exchange=Indicates whether or not the exchange was secure.
undertow.console-access-log.attributes.ssl-cipher=The SSL cipher.
undertow.console-access-log.attributes.ssl-client-cert=The SSL client certificate.
undertow.console-access-log.attributes.ssl-session-id=The SSL session id.
undertow.console-access-log.attributes.stored-response=The stored response.
undertow.console-access-log.attributes.thread-name=The thread name of the current thread.
undertow.console-access-log.attributes.transport-protocol=The protocol used to transmit messages on this connection.
undertow.console-access-log.attributes.key=The key for the structured output.
undertow.console-access-log.attributes.key-prefix=The prefix used to help keep unique keys. The name will be appended \
to the prefix if the prefix is defined. Otherwise just the name will be used as the key for the structured data.
undertow.console-access-log.attributes.names=A list of names used to resolve the exchange values.
undertow.console-access-log.attributes.obfuscated=Indicates whether or not the IP address should be obfuscated.
undertow.console-access-log.include-host-name=Indicates whether or not the host name should included in the JSON \
structured output. If set to true the key will be hostName in the structured data and the value will be the host \
this console-access-log belongs to.
undertow.console-access-log.metadata=Any additional metadata to add to the JSON structured output.
undertow.console-access-log.predicate=Predicate that determines if the request should be logged.
undertow.console-access-log.worker=Name of the worker to use for logging.
undertow.single-sign-on=An SSO authentication mechanism configuration.
undertow.single-sign-on.add=Adds an SSO authentication mechanism.
undertow.single-sign-on.remove=Removes the SSO authentication mechanism.

Large diffs are not rendered by default.

@@ -24,7 +24,7 @@
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
<config>
<extension-module>org.wildfly.extension.undertow</extension-module>
<subsystem xmlns="urn:jboss:domain:undertow:8.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<subsystem xmlns="urn:jboss:domain:undertow:9.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default" />
<server name="default-server">
<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true" />
@@ -24,7 +24,7 @@
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
<config>
<extension-module>org.wildfly.extension.undertow</extension-module>
<subsystem xmlns="urn:jboss:domain:undertow:8.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<subsystem xmlns="urn:jboss:domain:undertow:9.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default" />
<server name="default-server">
<?AJP?>
@@ -0,0 +1,58 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.wildfly.extension.undertow;

import java.io.IOException;

import org.jboss.as.subsystem.test.KernelServices;
import org.jboss.as.subsystem.test.KernelServicesBuilder;
import org.junit.Test;

/**
* This is the barebone test example that tests subsystem
*
* @author <a href="mailto:tomaz.cerar@redhat.com">Tomaz Cerar</a>
*/
public class UndertowSubsystem80TestCase extends AbstractUndertowSubsystemTestCase {

private final String virtualHostName = "some-server";
private final int flag = 1;

@Override
protected String getSubsystemXml() throws IOException {
return readResource("undertow-8.0.xml");
}

@Override
protected String getSubsystemXsdPath() throws Exception {
return "schema/wildfly-undertow_8_0.xsd";
}

protected KernelServices standardSubsystemTest(String configId, boolean compareXml) throws Exception {
return super.standardSubsystemTest(configId, false);
}

@Test
public void testRuntime() throws Exception {
setProperty();
KernelServicesBuilder builder = createKernelServicesBuilder(RUNTIME).setSubsystemXml(getSubsystemXml());
KernelServices mainServices = builder.build();
testRuntime(mainServices, virtualHostName, flag);
testRuntimeOther(mainServices);
testRuntimeLast(mainServices);
}
}
@@ -40,12 +40,12 @@

@Override
protected String getSubsystemXml() throws IOException {
return readResource("undertow-8.0.xml");
return readResource("undertow-9.0.xml");
}

@Override
protected String getSubsystemXsdPath() throws Exception {
return "schema/wildfly-undertow_8_0.xsd";
return "schema/wildfly-undertow_9_0.xsd";
}

@Override
@@ -32,6 +32,7 @@

import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.transform.OperationTransformer.TransformedOperation;
import org.jboss.as.model.test.FailedOperationTransformationConfig;
import org.jboss.as.model.test.ModelTestControllerVersion;
@@ -73,8 +74,7 @@ public void testTransformersEAP_7_1_0() throws Exception {

@Test
public void testTransformersEAP_7_2_0() throws Exception {
// TODO Enable once we can transform to 7.2
//testTransformers(ModelTestControllerVersion.EAP_7_1_0, "7.2", EAP7_2_0);
testTransformers(ModelTestControllerVersion.EAP_7_2_0, "7.2", EAP7_2_0);
}

@Test
@@ -135,6 +135,7 @@ public void testRejectTransformersEAP_7_0_0() throws Exception {
.addFailedAttribute(ajpAddress,
new FailedOperationTransformationConfig.NewAttributesConfig(
ALLOW_UNESCAPED_CHARACTERS_IN_URL, RFC6265_COOKIE_VALIDATION))
.addFailedAttribute(hostAddress.append(PathElement.pathElement(Constants.SETTING, "console-access-log")), FailedOperationTransformationConfig.REJECTED_RESOURCE)
);
}

@@ -172,14 +173,18 @@ public void testRejectTransformersEAP_7_1_0() throws Exception {
.addFailedAttribute(ajpAddress,
new FailedOperationTransformationConfig.NewAttributesConfig(
ALLOW_UNESCAPED_CHARACTERS_IN_URL))
.addFailedAttribute(hostAddress.append(PathElement.pathElement(Constants.SETTING, "console-access-log")), FailedOperationTransformationConfig.REJECTED_RESOURCE)
);
}

@Test
public void testRejectTransformersEAP_7_2_0() throws Exception {
// TODO Enable once we can transform to 7.2
//doRejectTest(ModelTestControllerVersion.EAP_7_1_0, EAP7_2_0, new FailedOperationTransformationConfig()
// );
final PathAddress subsystemAddress = PathAddress.pathAddress(UndertowExtension.SUBSYSTEM_PATH);
final PathAddress serverAddress = subsystemAddress.append(UndertowExtension.SERVER_PATH);
final PathAddress hostAddress = serverAddress.append(UndertowExtension.HOST_PATH);
doRejectTest(ModelTestControllerVersion.EAP_7_2_0, EAP7_2_0, new FailedOperationTransformationConfig()
.addFailedAttribute(hostAddress.append(PathElement.pathElement(Constants.SETTING, "console-access-log")), FailedOperationTransformationConfig.REJECTED_RESOURCE)
);
}

@Test
@@ -289,11 +294,12 @@ protected AdditionalInitialization createAdditionalInitialization() {
}

private void addExtraMavenUrls(ModelTestControllerVersion controllerVersion, LegacyKernelServicesInitializer init) throws Exception {
if (controllerVersion == ModelTestControllerVersion.EAP_7_1_0) {
if (controllerVersion == ModelTestControllerVersion.EAP_7_1_0 || controllerVersion == ModelTestControllerVersion.EAP_7_2_0) {
init.addMavenResourceURL(controllerVersion.getMavenGroupId() + ":wildfly-clustering-common:" + controllerVersion.getMavenGavVersion());
init.addMavenResourceURL(controllerVersion.getMavenGroupId() + ":wildfly-web-common:" + controllerVersion.getMavenGavVersion());
init.addMavenResourceURL("io.undertow:undertow-servlet:2.0.4.Final");
init.addMavenResourceURL("io.undertow:undertow-core:2.0.4.Final");
// The version here appears to be required to be set to the current version of undertow
init.addMavenResourceURL("io.undertow:undertow-servlet:2.0.20.Final");
init.addMavenResourceURL("io.undertow:undertow-core:2.0.20.Final");
}
}

@@ -0,0 +1,114 @@
<!--
~ Copyright 2019 Red Hat, Inc.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<subsystem xmlns="urn:jboss:domain:undertow:9.0" default-server="some-server" default-servlet-container="myContainer" default-virtual-host="default-virtual-host" instance-id="some-id" statistics-enabled="true">
<byte-buffer-pool name="test" thread-local-cache-size="45" buffer-size="1000" direct="false" leak-detection-percent="50" max-pool-size="1000"/>
<buffer-cache buffer-size="1025" buffers-per-region="1054" max-regions="15" name="default"/>
<buffer-cache buffer-size="1025" buffers-per-region="1054" max-regions="15" name="extra"/>
<server default-host="other-host" name="some-server" servlet-container="myContainer">
<ajp-listener disallowed-methods="FOO TRACE" allow-unescaped-characters-in-url="true" max-parameters="5000" name="ajp-connector" no-request-timeout="10000" receive-buffer="5000" redirect-socket="ajps" request-parse-timeout="2000" resolve-peer-address="true" secure="true" send-buffer="50000" socket-binding="ajp" tcp-backlog="500" tcp-keep-alive="true" max-ajp-packet-size="10000"/>
<http-listener always-set-keep-alive="${prop.smth:false}" certificate-forwarding="true" name="default" proxy-address-forwarding="${prop.smth:false}" redirect-socket="ajp" resolve-peer-address="true" socket-binding="http" proxy-protocol="true"/>
<http-listener max-cookies="100" max-headers="30" max-parameters="30" max-post-size="100000" name="second" redirect-socket="https-non-default" require-host-http11="true" socket-binding="http-2" url-charset="windows-1250"/>
<http-listener max-cookies="100" max-headers="30" max-parameters="30" max-post-size="100000" name="no-redirect" socket-binding="http-3" url-charset="windows-1250" worker="non-default"/>
<https-listener disallowed-methods="" max-buffered-request-size="50000" max-connections="100" name="https" record-request-start-time="true" require-host-http11="true" resolve-peer-address="true" security-realm="UndertowRealm" socket-binding="https-non-default" verify-client="REQUESTED"/>
<https-listener certificate-forwarding="true" allow-unescaped-characters-in-url="true" enabled-cipher-suites="ALL:!MD5:!DHA" enabled-protocols="SSLv3, TLSv1.2" name="https-2" proxy-address-forwarding="true" read-timeout="-1" security-realm="UndertowRealm" socket-binding="https-2" write-timeout="-1"/>
<https-listener disallowed-methods="" max-buffered-request-size="50000" max-connections="100" name="https-3" record-request-start-time="true" resolve-peer-address="true" socket-binding="https-3" ssl-context="TestContext" rfc6265-cookie-validation="true" proxy-protocol="true"/>
<!--<https-listener disallowed-methods="" max-buffered-request-size="50000" max-connections="100" name="https-4" record-request-start-time="true" resolve-peer-address="true" socket-binding="https-4" />--> <!-- this one must fail-->
<host alias="localhost,some.host" default-response-code="503" default-web-module="something.war" name="default-virtual-host">
<location handler="welcome-content" name="/">
<filter-ref name="limit-connections"/>
<filter-ref name="headers" priority="${some.priority:10}"/>
<filter-ref name="404-handler"/>
<filter-ref name="static-gzip" predicate="path-suffix('.js')"/>
</location>
<access-log directory="${jboss.server.server.dir}" pattern="REQ %{i,test-header}" predicate="not path-suffix(*.css)" prefix="access" rotate="false"/>
<console-access-log predicate="not path-suffix(*.css)" worker="default">
<attributes>
<authentication-type/>
<date-time date-format="yyyy-MM-dd'T'HH:mm:ss" key="timestamp"/>
<query-parameter>
<name value="test"/>
</query-parameter>
<request-header key-prefix="requestHeader">
<name value="Content-Type"/>
<name value="Content-Encoding"/>
</request-header>
<response-code/>
<response-time time-unit="MICROSECONDS"/>
</attributes>
<metadata>
<property name="@version" value="1"/>
<property name="host" value="${jboss.host.name:localhost}"/>
</metadata>
</console-access-log>
<single-sign-on cookie-name="SSOID" domain="${prop.domain:myDomain}" http-only="true" path="/path" secure="true"/>
</host>
<host alias="www.mysite.com,${prop.value:default-alias}" default-response-code="501" default-web-module="something-else.war" disable-console-redirect="true" name="other-host" queue-requests-on-start="false">
<location handler="welcome-content" name="/">
<filter-ref name="limit-connections"/>
<filter-ref name="headers"/>
<filter-ref name="static-gzip" predicate="path-suffix('.js') or path-suffix('.css') or path-prefix('/resources')"/>
<filter-ref name="404-handler"/>
<filter-ref name="mod-cluster"/>
</location>
<filter-ref name="headers"/>
<http-invoker http-authentication-factory="factory" path="services"/>
</host>
</server>
<servlet-container default-buffer-cache="extra" default-encoding="utf-8" default-session-timeout="100" directory-listing="true" eager-filter-initialization="true" ignore-flush="true" name="myContainer" proactive-authentication="${prop.pro:false}" use-listener-encoding="${prop.foo:false}" disable-session-id-reuse="${prop.foo:true}" disable-file-watch-service="${prop.foo:true}" file-cache-metadata-size="50" file-cache-max-file-size="5000" file-cache-time-to-live="1000" default-cookie-version="1">
<jsp-config check-interval="${prop.check-interval:20}" disabled="${prop.disabled:false}" display-source-fragment="${prop.display-source-fragment:true}" dump-smap="${prop.dump-smap:true}" error-on-use-bean-invalid-class-attribute="${prop.error-on-use-bean-invalid-class-attribute:true}" generate-strings-as-char-arrays="${prop.generate-strings-as-char-arrays:true}" java-encoding="${prop.java-encoding:utf-8}" keep-generated="${prop.keep-generated:true}" mapped-file="${prop.mapped-file:true}" modification-test-interval="${prop.modification-test-interval:1000}" optimize-scriptlets="${prop.optimise-scriptlets:true}" recompile-on-fail="${prop.recompile-on-fail:true}" scratch-dir="${prop.scratch-dir:/some/dir}" smap="${prop.smap:true}" source-vm="${prop.source-vm:1.7}" tag-pooling="${prop.tag-pooling:true}" target-vm="${prop.target-vm:1.7}" trim-spaces="${prop.trim-spaces:true}" x-powered-by="${prop.x-powered-by:true}"/>
<session-cookie comment="session cookie" domain="example.com" http-only="true" max-age="1000" name="MYSESSIONCOOKIE" secure="true"/>
<websockets deflater-level="0" dispatch-to-worker="false" per-message-deflate="false"/>
<mime-mappings>
<mime-mapping name="txt" value="text/plain"/>
</mime-mappings>
<welcome-files>
<welcome-file name="index.seam"/>
</welcome-files>
<crawler-session-management session-timeout="2" user-agents=".*googlebot.*"/>
</servlet-container>
<handlers>
<file case-sensitive="false" directory-listing="true" follow-symlink="true" name="welcome-content" path="${jboss.home.dir}" safe-symlink-paths="/path/to/folder /second/path"/>
<reverse-proxy connection-idle-timeout="60" connections-per-thread="30" max-retries="10" name="reverse-proxy">
<host instance-id="myRoute" name="server1" outbound-socket-binding="ajp-remote" path="/test" scheme="ajp" ssl-context="TestContext"/>
<host instance-id="myRoute" name="server2" outbound-socket-binding="ajp-remote" path="/test" scheme="ajp" ssl-context="TestContext"/>
</reverse-proxy>
</handlers>
<filters>
<request-limit max-concurrent-requests="15000" name="limit-connections" queue-size="100"/>
<response-header header-name="MY_HEADER" header-value="someValue" name="headers"/>
<gzip name="static-gzip"/>
<error-page code="404" name="404-handler" path="/opt/data/404.html"/>
<mod-cluster advertise-frequency="1000" advertise-path="/foo" advertise-protocol="ajp"
advertise-socket-binding="advertise-socket-binding" broken-node-timeout="1000"
cached-connections-per-thread="10" connection-idle-timeout="10"
failover-strategy="DETERMINISTIC" health-check-interval="600"
management-access-predicate="method[GET]" management-socket-binding="test3"
max-request-time="1000" max-retries="10" name="mod-cluster"
security-key="password" ssl-context="TestContext" max-ajp-packet-size="10000" />
<filter class-name="io.undertow.server.handlers.HttpTraceHandler" module="io.undertow.core" name="custom-filter"/>
<expression-filter expression="dump-request" name="requestDumper"/>
<rewrite name="redirects" redirect="true" target="'/foo/'"/>
</filters>
<application-security-domains>
<application-security-domain enable-jacc="true" http-authentication-factory="elytron-factory" name="other" override-deployment-config="true" enable-jaspi="false" integrated-jaspi="false">
<single-sign-on client-ssl-context="my-ssl-context" cookie-name="SSOID" domain="${prop.domain:myDomain}" http-only="true" key-alias="my-key-alias" key-store="my-key-store" path="/path" secure="true">
<credential-reference alias="my-credential-alias" store="my-credential-store" type="password"/>
</single-sign-on>
</application-security-domain>
<application-security-domain security-domain="elytron-domain" name="domain-ref" />
</application-security-domains>
</subsystem>
@@ -20,7 +20,7 @@
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->

<subsystem xmlns="urn:jboss:domain:undertow:8.0" default-server="default-server" default-servlet-container="myContainer" default-virtual-host="default-virtual-host" instance-id="some-id" statistics-enabled="true">
<subsystem xmlns="urn:jboss:domain:undertow:9.0" default-server="default-server" default-servlet-container="myContainer" default-virtual-host="default-virtual-host" instance-id="some-id" statistics-enabled="true">
<buffer-cache buffer-size="1025" buffers-per-region="1054" max-regions="15" name="default"/>
<buffer-cache buffer-size="1025" buffers-per-region="1054" max-regions="15" name="extra"/>
<server default-host="other-host" name="default-server" servlet-container="myContainer">
@@ -39,6 +39,25 @@
<filter-ref name="static-gzip" predicate="path-suffix('.js')"/>
</location>
<access-log directory="${jboss.server.server.dir}" pattern="REQ %{i,test-header}" predicate="not path-suffix(*.css)" prefix="access" rotate="false"/>
<console-access-log predicate="not path-suffix(*.css)">
<attributes>
<date-time date-format="yyyy-MM-dd'T'HH:mm:ss" key="timestamp"/>
<query-parameter>
<name value="test"/>
<name value="foo"/>
</query-parameter>
<response-code/>
<response-header key-prefix="responseHeader">
<name value="Content-Type"/>
<name value="Content-Encoding"/>
</response-header>
<response-time time-unit="MICROSECONDS"/>
</attributes>
<metadata>
<property name="@version" value="1"/>
<property name="qualifiedHost" value="${jboss.qualified.host.name:unknown}"/>
</metadata>
</console-access-log>
<single-sign-on cookie-name="SSOID" domain="${prop.domain:myDomain}" http-only="true" path="/path" secure="true"/>
</host>
<host alias="www.mysite.com,${prop.value:default-alias}" default-response-code="501" default-web-module="something-else.war" disable-console-redirect="true" name="other-host">
@@ -20,7 +20,7 @@
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->

<subsystem xmlns="urn:jboss:domain:undertow:6.0" default-server="some-server" default-servlet-container="myContainer" default-virtual-host="default-virtual-host" instance-id="some-id" statistics-enabled="true">
<subsystem xmlns="urn:jboss:domain:undertow:9.0" default-server="some-server" default-servlet-container="myContainer" default-virtual-host="default-virtual-host" instance-id="some-id" statistics-enabled="true">
<buffer-cache buffer-size="1025" buffers-per-region="1054" max-regions="15" name="default"/>
<buffer-cache buffer-size="1025" buffers-per-region="1054" max-regions="15" name="extra"/>
<byte-buffer-pool name="test-buffers" buffer-size="1000" leak-detection-percent="0" direct="true" max-pool-size="10" thread-local-cache-size="1" />
@@ -40,6 +40,25 @@
<filter-ref name="static-gzip" predicate="path-suffix('.js')"/>
</location>
<access-log directory="${jboss.server.server.dir}" pattern="REQ %{i,test-header}" predicate="not path-suffix(*.css)" prefix="access" rotate="false"/>
<console-access-log predicate="not path-suffix(*.css)">
<attributes>
<date-time date-format="yyyy-MM-dd'T'HH:mm:ss" key="timestamp"/>
<query-parameter>
<name value="test"/>
<name value="foo"/>
</query-parameter>
<response-code/>
<response-header key-prefix="responseHeader">
<name value="Content-Type"/>
<name value="Content-Encoding"/>
</response-header>
<response-time time-unit="MICROSECONDS"/>
</attributes>
<metadata>
<property name="@version" value="1"/>
<property name="qualifiedHost" value="${jboss.qualified.host.name:unknown}"/>
</metadata>
</console-access-log>
<single-sign-on cookie-name="SSOID" domain="${prop.domain:myDomain}" http-only="true" path="/path" secure="true"/>
</host>
<host alias="www.mysite.com,${prop.value:default-alias}" default-response-code="501" default-web-module="something-else.war" disable-console-redirect="true" name="other-host">