Index: 3rdParty_sources/undertow/io/undertow/Handlers.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/Handlers.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/Handlers.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,512 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow;
+
+import io.undertow.attribute.ExchangeAttribute;
+import io.undertow.predicate.Predicate;
+import io.undertow.predicate.PredicateParser;
+import io.undertow.predicate.PredicatesHandler;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.JvmRouteHandler;
+import io.undertow.server.RoutingHandler;
+import io.undertow.server.handlers.AccessControlListHandler;
+import io.undertow.server.handlers.DateHandler;
+import io.undertow.server.handlers.DisableCacheHandler;
+import io.undertow.server.handlers.ExceptionHandler;
+import io.undertow.server.handlers.GracefulShutdownHandler;
+import io.undertow.server.handlers.HttpContinueAcceptingHandler;
+import io.undertow.server.handlers.HttpContinueReadHandler;
+import io.undertow.server.handlers.HttpTraceHandler;
+import io.undertow.server.handlers.IPAddressAccessControlHandler;
+import io.undertow.server.handlers.NameVirtualHostHandler;
+import io.undertow.server.handlers.PathHandler;
+import io.undertow.server.handlers.PathTemplateHandler;
+import io.undertow.server.handlers.PredicateContextHandler;
+import io.undertow.server.handlers.PredicateHandler;
+import io.undertow.server.handlers.ProxyPeerAddressHandler;
+import io.undertow.server.handlers.RedirectHandler;
+import io.undertow.server.handlers.RequestDumpingHandler;
+import io.undertow.server.handlers.RequestLimit;
+import io.undertow.server.handlers.RequestLimitingHandler;
+import io.undertow.server.handlers.ResponseCodeHandler;
+import io.undertow.server.handlers.SetAttributeHandler;
+import io.undertow.server.handlers.SetHeaderHandler;
+import io.undertow.server.handlers.URLDecodingHandler;
+import io.undertow.server.handlers.builder.PredicatedHandler;
+import io.undertow.server.handlers.proxy.ProxyClient;
+import io.undertow.server.handlers.proxy.ProxyHandler;
+import io.undertow.server.handlers.resource.ResourceHandler;
+import io.undertow.server.handlers.resource.ResourceManager;
+import io.undertow.websockets.WebSocketConnectionCallback;
+import io.undertow.websockets.WebSocketProtocolHandshakeHandler;
+
+import java.util.List;
+
+/**
+ * Utility class with convenience methods for dealing with handlers
+ *
+ * @author Stuart Douglas
+ */
+public class Handlers {
+
+ /**
+ * Creates a new path handler, with the default handler specified
+ *
+ * @param defaultHandler The default handler
+ * @return A new path handler
+ */
+ public static PathHandler path(final HttpHandler defaultHandler) {
+ return new PathHandler(defaultHandler);
+ }
+
+ /**
+ * Creates a new path handler
+ *
+ * @return A new path handler
+ */
+ public static PathHandler path() {
+ return new PathHandler();
+ }
+
+ /**
+ *
+ * @return a new path template handler
+ */
+ public static PathTemplateHandler pathTemplate() {
+ return new PathTemplateHandler();
+ }
+
+ /**
+ *
+ * @param rewriteQueryParams If the query params should be rewritten
+ * @return The routing handler
+ */
+ public static RoutingHandler routing(boolean rewriteQueryParams) {
+ return new RoutingHandler(rewriteQueryParams);
+ }
+
+ /**
+ *
+ * @return a new routing handler
+ */
+ public static RoutingHandler routing() {
+ return new RoutingHandler();
+ }
+
+ /**
+ *
+ * @param rewriteQueryParams If the query params should be rewritten
+ * @return The path template handler
+ */
+ public static PathTemplateHandler pathTemplate(boolean rewriteQueryParams) {
+ return new PathTemplateHandler(rewriteQueryParams);
+ }
+
+
+ /**
+ * Creates a new virtual host handler
+ *
+ * @return A new virtual host handler
+ */
+ public static NameVirtualHostHandler virtualHost() {
+ return new NameVirtualHostHandler();
+ }
+
+ /**
+ * Creates a new virtual host handler using the provided default handler
+ *
+ * @return A new virtual host handler
+ */
+ public static NameVirtualHostHandler virtualHost(final HttpHandler defaultHandler) {
+ return new NameVirtualHostHandler().setDefaultHandler(defaultHandler);
+ }
+
+ /**
+ * Creates a new virtual host handler that uses the provided handler as the root handler for the given hostnames.
+ *
+ * @param hostHandler The host handler
+ * @param hostnames The host names
+ * @return A new virtual host handler
+ */
+ public static NameVirtualHostHandler virtualHost(final HttpHandler hostHandler, String... hostnames) {
+ NameVirtualHostHandler handler = new NameVirtualHostHandler();
+ for (String host : hostnames) {
+ handler.addHost(host, hostHandler);
+ }
+ return handler;
+ }
+
+ /**
+ * Creates a new virtual host handler that uses the provided handler as the root handler for the given hostnames.
+ *
+ * @param defaultHandler The default handler
+ * @param hostHandler The host handler
+ * @param hostnames The host names
+ * @return A new virtual host handler
+ */
+ public static NameVirtualHostHandler virtualHost(final HttpHandler defaultHandler, final HttpHandler hostHandler, String... hostnames) {
+ return virtualHost(hostHandler, hostnames).setDefaultHandler(defaultHandler);
+ }
+
+ /**
+ * @param sessionHandler The web socket session handler
+ * @return The web socket handler
+ */
+ public static WebSocketProtocolHandshakeHandler websocket(final WebSocketConnectionCallback sessionHandler) {
+ return new WebSocketProtocolHandshakeHandler(sessionHandler);
+ }
+
+ /**
+ * @param sessionHandler The web socket session handler
+ * @param next The handler to invoke if the web socket connection fails
+ * @return The web socket handler
+ */
+ public static WebSocketProtocolHandshakeHandler websocket(final WebSocketConnectionCallback sessionHandler, final HttpHandler next) {
+ return new WebSocketProtocolHandshakeHandler(sessionHandler, next);
+ }
+
+ /**
+ * Return a new resource handler
+ *
+ * @param resourceManager The resource manager to use
+ * @return A new resource handler
+ */
+ public static ResourceHandler resource(final ResourceManager resourceManager) {
+ return new ResourceHandler(resourceManager).setDirectoryListingEnabled(false);
+ }
+
+ /**
+ * Returns a new redirect handler
+ *
+ * @param location The redirect location
+ * @return A new redirect handler
+ */
+ public static RedirectHandler redirect(final String location) {
+ return new RedirectHandler(location);
+ }
+
+ /**
+ * Returns a new HTTP trace handler. This handler will handle HTTP TRACE
+ * requests as per the RFC.
+ *
+ * WARNING: enabling trace requests may leak information, in general it is recommended that
+ * these be disabled for security reasons.
+ *
+ * @param next The next handler in the chain
+ * @return A HTTP trace handler
+ */
+ public static HttpTraceHandler trace(final HttpHandler next) {
+ return new HttpTraceHandler(next);
+ }
+
+ /**
+ * Returns a new HTTP handler that sets the Date: header.
+ *
+ * This is no longer necessary, as it is handled by the connectors directly.
+ *
+ * @param next The next handler in the chain
+ * @return A new date handler
+ */
+ @Deprecated
+ public static DateHandler date(final HttpHandler next) {
+ return new DateHandler(next);
+ }
+
+ /**
+ * Returns a new predicate handler, that will delegate to one of the two provided handlers based on the value of the
+ * provided predicate.
+ *
+ * @param predicate The predicate
+ * @param trueHandler The handler that will be executed if the predicate is true
+ * @param falseHandler The handler that will be exected if the predicate is false
+ * @return A new predicate handler
+ * @see Predicate
+ * @see io.undertow.predicate.Predicates
+ */
+ public static PredicateHandler predicate(final Predicate predicate, final HttpHandler trueHandler, final HttpHandler falseHandler) {
+ return new PredicateHandler(predicate, trueHandler, falseHandler);
+ }
+
+ /**
+ * @param next The next handler
+ * @return a handler that sets up a new predicate context
+ */
+ public static HttpHandler predicateContext(HttpHandler next) {
+ return new PredicateContextHandler(next);
+ }
+
+ public static PredicatesHandler predicates(final List handlers, HttpHandler next) {
+ final PredicatesHandler predicatesHandler = new PredicatesHandler(next);
+ for(PredicatedHandler handler : handlers) {
+ predicatesHandler.addPredicatedHandler(handler);
+ }
+ return predicatesHandler;
+ }
+
+ /**
+ * Returns a handler that sets a response header
+ *
+ * @param next The next handler in the chain
+ * @param headerName The name of the header
+ * @param headerValue The header value
+ * @return A new set header handler
+ */
+ public static SetHeaderHandler header(final HttpHandler next, final String headerName, final String headerValue) {
+ return new SetHeaderHandler(next, headerName, headerValue);
+ }
+
+ /**
+ * Returns a new handler that can allow or deny access to a resource based on IP address
+ *
+ * @param next The next handler in the chain
+ * @param defaultAllow Determine if a non-matching address will be allowed by default
+ * @return A new IP access control handler
+ */
+ public static final IPAddressAccessControlHandler ipAccessControl(final HttpHandler next, boolean defaultAllow) {
+ return new IPAddressAccessControlHandler(next).setDefaultAllow(defaultAllow);
+ }
+
+ /**
+ * Returns a new handler that can allow or deny access to a resource based an at attribute of the exchange
+ *
+ * @param next The next handler in the chain
+ * @param defaultAllow Determine if a non-matching user agent will be allowed by default
+ * @return A new user agent access control handler
+ */
+ public static final AccessControlListHandler acl(final HttpHandler next, boolean defaultAllow, ExchangeAttribute attribute) {
+ return new AccessControlListHandler(next, attribute).setDefaultAllow(defaultAllow);
+ }
+
+ /**
+ * A handler that automatically handles HTTP 100-continue responses, by sending a continue
+ * response when the first attempt is made to read from the request channel.
+ *
+ * @param next The next handler in the chain
+ * @return A new continue handler
+ */
+ public static final HttpContinueReadHandler httpContinueRead(final HttpHandler next) {
+ return new HttpContinueReadHandler(next);
+ }
+
+ /**
+ * Returns a handler that sends back a HTTP 100 continue response if the given predicate resolves to true.
+ *
+ * This handler differs from the one returned by {@link #httpContinueRead(io.undertow.server.HttpHandler)} in
+ * that it will eagerly send the response, and not wait for the first read attempt.
+ *
+ * @param next The next handler
+ * @param accept The predicate used to determine if the request should be accepted
+ * @return The accepting handler
+ */
+ public static final HttpContinueAcceptingHandler httpContinueAccepting(final HttpHandler next, final Predicate accept) {
+ return new HttpContinueAcceptingHandler(next, accept);
+ }
+
+ /**
+ * Returns a handler that sends back a HTTP 100 continue response to all requests.
+ *
+ * This handler differs from the one returned by {@link #httpContinueRead(io.undertow.server.HttpHandler)} in
+ * that it will eagerly send the response, and not wait for the first read attempt.
+ *
+ * @param next The next handler
+ * @return The accepting handler
+ */
+ public static final HttpContinueAcceptingHandler httpContinueAccepting(final HttpHandler next) {
+ return new HttpContinueAcceptingHandler(next);
+ }
+
+ /**
+ * A handler that will decode the URL, query parameters and to the specified charset.
+ *
+ * If you are using this handler you must set the {@link io.undertow.UndertowOptions#DECODE_URL} parameter to false.
+ *
+ * This is not as efficient as using the parsers built in UTF-8 decoder. Unless you need to decode to something other
+ * than UTF-8 you should rely on the parsers decoding instead.
+ *
+ * @param next The next handler in the chain
+ * @param charset The charset to decode to
+ * @return a new url decoding handler
+ */
+ public static final URLDecodingHandler urlDecoding(final HttpHandler next, final String charset) {
+ return new URLDecodingHandler(next, charset);
+ }
+
+ /**
+ * Returns an attribute setting handler that can be used to set an arbitrary attribute on the exchange.
+ * This includes functions such as adding and removing headers etc.
+ *
+ * @param next The next handler
+ * @param attribute The attribute to set, specified as a string presentation of an {@link io.undertow.attribute.ExchangeAttribute}
+ * @param value The value to set, specified an a string representation of an {@link io.undertow.attribute.ExchangeAttribute}
+ * @param classLoader The class loader to use to parser the exchange attributes
+ * @return The handler
+ */
+ public static SetAttributeHandler setAttribute(final HttpHandler next, final String attribute, final String value, final ClassLoader classLoader) {
+ return new SetAttributeHandler(next, attribute, value, classLoader);
+ }
+
+ /**
+ * Creates the set of handlers that are required to perform a simple rewrite.
+ * @param condition The rewrite condition
+ * @param target The rewrite target if the condition matches
+ * @param next The next handler
+ * @return
+ */
+ public static HttpHandler rewrite(final String condition, final String target, final ClassLoader classLoader, final HttpHandler next) {
+ return predicateContext(predicate(PredicateParser.parse(condition, classLoader), setAttribute(next, "%R", target, classLoader), next));
+ }
+
+ /**
+ * Returns a new handler that decodes the URL and query parameters into the specified charset, assuming it
+ * has not already been done by the connector. For this handler to take effect the parameter
+ * {@link UndertowOptions#DECODE_URL} must have been set to false.
+ *
+ * @param charset The charset to decode
+ * @param next The next handler
+ * @return A handler that decodes the URL
+ */
+ public static HttpHandler urlDecodingHandler(final String charset, final HttpHandler next) {
+ return new URLDecodingHandler(next, charset);
+ }
+
+
+ /**
+ * Returns a new handler that can be used to wait for all requests to finish before shutting down the server gracefully.
+ *
+ * @param next The next http handler
+ * @return The graceful shutdown handler
+ */
+ public static GracefulShutdownHandler gracefulShutdown(HttpHandler next) {
+ return new GracefulShutdownHandler(next);
+ }
+
+ /**
+ * Returns a new handler that sets the peer address based on the X-Forwarded-For and
+ * X-Forwarded-Proto header
+ * @param next The next http handler
+ * @return The handler
+ */
+ public static ProxyPeerAddressHandler proxyPeerAddress(HttpHandler next) {
+ return new ProxyPeerAddressHandler(next);
+ }
+
+ /**
+ * Handler that appends the JVM route to the session cookie
+ * @param sessionCookieName The session cookie name
+ * @param jvmRoute The JVM route to append
+ * @param next The next handler
+ * @return The handler
+ */
+ public static JvmRouteHandler jvmRoute(final String sessionCookieName, final String jvmRoute, HttpHandler next) {
+ return new JvmRouteHandler(next, sessionCookieName, jvmRoute);
+ }
+
+ /**
+ * Returns a handler that limits the maximum number of requests that can run at a time.
+ *
+ * @param maxRequest The maximum number of requests
+ * @param queueSize The maximum number of queued requests
+ * @param next The next handler
+ * @return The handler
+ */
+ public static RequestLimitingHandler requestLimitingHandler(final int maxRequest, final int queueSize, HttpHandler next) {
+ return new RequestLimitingHandler(maxRequest, queueSize, next);
+ }
+
+ /**
+ * Returns a handler that limits the maximum number of requests that can run at a time.
+ *
+ * @param requestLimit The request limit object that can be shared between handlers, to apply the same limits across multiple handlers
+ * @param next The next handler
+ * @return The handler
+ */
+ public static RequestLimitingHandler requestLimitingHandler(final RequestLimit requestLimit, HttpHandler next) {
+ return new RequestLimitingHandler(requestLimit, next);
+ }
+
+ /**
+ * Returns a handler that can act as a load balancing reverse proxy.
+ *
+ * @param proxyClient The proxy client to use to connect to the remote server
+ * @param maxRequestTime The maximum amount of time a request can be in progress before it is forcibly closed
+ * @param next The next handler to invoke if the proxy client does not know how to proxy the request
+ * @return The proxy handler
+ */
+ public static ProxyHandler proxyHandler(ProxyClient proxyClient, int maxRequestTime, HttpHandler next) {
+ return new ProxyHandler(proxyClient, maxRequestTime, next);
+ }
+ /**
+ * Returns a handler that can act as a load balancing reverse proxy.
+ *
+ * @param proxyClient The proxy client to use to connect to the remote server
+ * @param next The next handler to invoke if the proxy client does not know how to proxy the request
+ * @return The proxy handler
+ */
+ public static ProxyHandler proxyHandler(ProxyClient proxyClient, HttpHandler next) {
+ return new ProxyHandler(proxyClient, next);
+ }
+
+ /**
+ * Returns a handler that can act as a load balancing reverse proxy.
+ *
+ * @param proxyClient The proxy client to use to connect to the remote server
+ * @return The proxy handler
+ */
+ public static ProxyHandler proxyHandler(ProxyClient proxyClient) {
+ return new ProxyHandler(proxyClient, ResponseCodeHandler.HANDLE_404);
+ }
+
+ /**
+ * Handler that sets the headers that disable caching of the response
+ * @param next The next handler
+ * @return The handler
+ */
+ public static HttpHandler disableCache(final HttpHandler next) {
+ return new DisableCacheHandler(next);
+ }
+
+ /**
+ * Returns a handler that dumps requests to the log for debugging purposes.
+ *
+ * @param next The next handler
+ * @return The request dumping handler
+ */
+ public static HttpHandler requestDump(final HttpHandler next) {
+ return new RequestDumpingHandler(next);
+ }
+
+ /**
+ * Returns a handler that maps exceptions to additional handlers
+ * @param next The next handler
+ * @return The exception handler
+ */
+ public static ExceptionHandler exceptionHandler(final HttpHandler next) {
+ return new ExceptionHandler(next);
+ }
+
+ private Handlers() {
+
+ }
+
+ public static void handlerNotNull(final HttpHandler handler) {
+ if (handler == null) {
+ throw UndertowMessages.MESSAGES.handlerCannotBeNull();
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/Undertow.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/Undertow.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/Undertow.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,395 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow;
+
+import io.undertow.security.api.AuthenticationMode;
+import io.undertow.security.api.GSSAPIServerSubjectFactory;
+import io.undertow.security.idm.IdentityManager;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.OpenListener;
+import io.undertow.server.protocol.ajp.AjpOpenListener;
+import io.undertow.server.protocol.http.HttpOpenListener;
+import io.undertow.server.protocol.spdy.SpdyOpenListener;
+import org.xnio.BufferAllocator;
+import org.xnio.ByteBufferSlicePool;
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.IoUtils;
+import org.xnio.Option;
+import org.xnio.OptionMap;
+import org.xnio.Options;
+import org.xnio.Pool;
+import org.xnio.StreamConnection;
+import org.xnio.Xnio;
+import org.xnio.XnioWorker;
+import org.xnio.channels.AcceptingChannel;
+import org.xnio.ssl.JsseXnioSsl;
+import org.xnio.ssl.SslConnection;
+import org.xnio.ssl.XnioSsl;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Convenience class used to build an Undertow server.
+ *
+ * TODO: This API is still a work in progress
+ *
+ * @author Stuart Douglas
+ */
+public class Undertow {
+
+ private final int bufferSize;
+ private final int buffersPerRegion;
+ private final int ioThreads;
+ private final int workerThreads;
+ private final boolean directBuffers;
+ private final List listeners = new ArrayList<>();
+ private final HttpHandler rootHandler;
+ private final OptionMap workerOptions;
+ private final OptionMap socketOptions;
+ private final OptionMap serverOptions;
+
+ private XnioWorker worker;
+ private List> channels;
+ private Xnio xnio;
+
+ private Undertow(Builder builder) {
+ this.bufferSize = builder.bufferSize;
+ this.buffersPerRegion = builder.buffersPerRegion;
+ this.ioThreads = builder.ioThreads;
+ this.workerThreads = builder.workerThreads;
+ this.directBuffers = builder.directBuffers;
+ this.listeners.addAll(builder.listeners);
+ this.rootHandler = builder.handler;
+ this.workerOptions = builder.workerOptions.getMap();
+ this.socketOptions = builder.socketOptions.getMap();
+ this.serverOptions = builder.serverOptions.getMap();
+ }
+
+ /**
+ * @return A builder that can be used to create an Undertow server instance
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public synchronized void start() {
+ xnio = Xnio.getInstance(Undertow.class.getClassLoader());
+ channels = new ArrayList<>();
+ try {
+ worker = xnio.createWorker(OptionMap.builder()
+ .set(Options.WORKER_IO_THREADS, ioThreads)
+ .set(Options.CONNECTION_HIGH_WATER, 1000000)
+ .set(Options.CONNECTION_LOW_WATER, 1000000)
+ .set(Options.WORKER_TASK_CORE_THREADS, workerThreads)
+ .set(Options.WORKER_TASK_MAX_THREADS, workerThreads)
+ .set(Options.TCP_NODELAY, true)
+ .set(Options.CORK, true)
+ .addAll(workerOptions)
+ .getMap());
+
+ OptionMap socketOptions = OptionMap.builder()
+ .set(Options.WORKER_IO_THREADS, ioThreads)
+ .set(Options.TCP_NODELAY, true)
+ .set(Options.REUSE_ADDRESSES, true)
+ .set(Options.BALANCING_TOKENS, 1)
+ .set(Options.BALANCING_CONNECTIONS, 2)
+ .addAll(this.socketOptions)
+ .getMap();
+
+
+ Pool buffers = new ByteBufferSlicePool(directBuffers ? BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR : BufferAllocator.BYTE_BUFFER_ALLOCATOR, bufferSize, bufferSize * buffersPerRegion);
+
+ for (ListenerConfig listener : listeners) {
+ if (listener.type == ListenerType.AJP) {
+ AjpOpenListener openListener = new AjpOpenListener(buffers, serverOptions, bufferSize);
+ openListener.setRootHandler(rootHandler);
+ ChannelListener> acceptListener = ChannelListeners.openListenerAdapter(openListener);
+ AcceptingChannel extends StreamConnection> server = worker.createStreamConnectionServer(new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port), acceptListener, socketOptions);
+ server.resumeAccepts();
+ channels.add(server);
+ } else {
+ OptionMap undertowOptions = OptionMap.builder().set(UndertowOptions.BUFFER_PIPELINED_DATA, true).addAll(serverOptions).getMap();
+ if (listener.type == ListenerType.HTTP) {
+ HttpOpenListener openListener = new HttpOpenListener(buffers, undertowOptions, bufferSize);
+ openListener.setRootHandler(rootHandler);
+ ChannelListener> acceptListener = ChannelListeners.openListenerAdapter(openListener);
+ AcceptingChannel extends StreamConnection> server = worker.createStreamConnectionServer(new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port), acceptListener, socketOptions);
+ server.resumeAccepts();
+ channels.add(server);
+ } else if (listener.type == ListenerType.HTTPS) {
+ OpenListener openListener = new HttpOpenListener(buffers, undertowOptions, bufferSize);
+ if(serverOptions.get(UndertowOptions.ENABLE_SPDY, false)) {
+ openListener = new SpdyOpenListener(buffers, new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1024, 1024), undertowOptions, bufferSize, (HttpOpenListener) openListener);
+ }
+ openListener.setRootHandler(rootHandler);
+ ChannelListener> acceptListener = ChannelListeners.openListenerAdapter(openListener);
+ XnioSsl xnioSsl;
+ if (listener.sslContext != null) {
+ xnioSsl = new JsseXnioSsl(xnio, OptionMap.create(Options.USE_DIRECT_BUFFERS, true), listener.sslContext);
+ } else {
+ xnioSsl = xnio.getSslProvider(listener.keyManagers, listener.trustManagers, OptionMap.create(Options.USE_DIRECT_BUFFERS, true));
+ }
+ AcceptingChannel sslServer = xnioSsl.createSslConnectionServer(worker, new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port), (ChannelListener) acceptListener, socketOptions);
+ sslServer.resumeAccepts();
+ channels.add(sslServer);
+ }
+ }
+
+ }
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized void stop() {
+ for (AcceptingChannel extends StreamConnection> channel : channels) {
+ IoUtils.safeClose(channel);
+ }
+ channels = null;
+ worker.shutdownNow();
+ worker = null;
+ xnio = null;
+ }
+
+
+ public static enum ListenerType {
+ HTTP,
+ HTTPS,
+ AJP
+ }
+
+ private static class ListenerConfig {
+ final ListenerType type;
+ final int port;
+ final String host;
+ final KeyManager[] keyManagers;
+ final TrustManager[] trustManagers;
+ final SSLContext sslContext;
+
+ private ListenerConfig(final ListenerType type, final int port, final String host, KeyManager[] keyManagers, TrustManager[] trustManagers) {
+ this.type = type;
+ this.port = port;
+ this.host = host;
+ this.keyManagers = keyManagers;
+ this.trustManagers = trustManagers;
+ this.sslContext = null;
+ }
+
+ private ListenerConfig(final ListenerType type, final int port, final String host, SSLContext sslContext) {
+ this.type = type;
+ this.port = port;
+ this.host = host;
+ this.keyManagers = null;
+ this.trustManagers = null;
+ this.sslContext = sslContext;
+ }
+ }
+
+ public static class LoginConfig {
+ private final IdentityManager identityManager;
+ private boolean basic;
+ private boolean digest;
+ private boolean kerberos;
+ private boolean form;
+ private String realmName;
+ private String errorPage, loginPage;
+ private GSSAPIServerSubjectFactory subjectFactory;
+ private AuthenticationMode authenticationMode = AuthenticationMode.PRO_ACTIVE;
+
+ public LoginConfig(final IdentityManager identityManager) {
+ this.identityManager = identityManager;
+ }
+
+ public LoginConfig basicAuth(final String realmName) {
+ if (digest) {
+ throw UndertowMessages.MESSAGES.authTypeCannotBeCombined("basic", "digest");
+ } else if (form) {
+ throw UndertowMessages.MESSAGES.authTypeCannotBeCombined("basic", "form");
+ }
+ basic = true;
+ this.realmName = realmName;
+ return this;
+ }
+
+ public LoginConfig digestAuth(final String realmName) {
+ if (basic) {
+ throw UndertowMessages.MESSAGES.authTypeCannotBeCombined("digest", "basic");
+ } else if (form) {
+ throw UndertowMessages.MESSAGES.authTypeCannotBeCombined("digest", "form");
+ }
+ digest = true;
+ this.realmName = realmName;
+ return this;
+ }
+
+ public LoginConfig kerberosAuth(GSSAPIServerSubjectFactory subjectFactory) {
+ kerberos = true;
+ this.subjectFactory = subjectFactory;
+ return this;
+ }
+
+ public LoginConfig formAuth(final String loginPage, final String errorPage) {
+ if (digest) {
+ throw UndertowMessages.MESSAGES.authTypeCannotBeCombined("form", "digest");
+ } else if (basic) {
+ throw UndertowMessages.MESSAGES.authTypeCannotBeCombined("form", "basic");
+ }
+ this.loginPage = loginPage;
+ this.errorPage = errorPage;
+ form = true;
+ return this;
+ }
+
+ public LoginConfig setAuthenticationMode(final AuthenticationMode authenticationMode) {
+ this.authenticationMode = authenticationMode;
+ return this;
+ }
+ }
+
+ public static final class Builder {
+
+ private int bufferSize;
+ private int buffersPerRegion;
+ private int ioThreads;
+ private int workerThreads;
+ private boolean directBuffers;
+ private final List listeners = new ArrayList<>();
+ private HttpHandler handler;
+
+ private final OptionMap.Builder workerOptions = OptionMap.builder();
+ private final OptionMap.Builder socketOptions = OptionMap.builder();
+ private final OptionMap.Builder serverOptions = OptionMap.builder();
+
+ private Builder() {
+ ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2);
+ workerThreads = ioThreads * 8;
+ long maxMemory = Runtime.getRuntime().maxMemory();
+ //smaller than 64mb of ram we use 512b buffers
+ if (maxMemory < 64 * 1024 * 1024) {
+ //use 512b buffers
+ directBuffers = false;
+ bufferSize = 512;
+ buffersPerRegion = 10;
+ } else if (maxMemory < 128 * 1024 * 1024) {
+ //use 1k buffers
+ directBuffers = true;
+ bufferSize = 1024;
+ buffersPerRegion = 10;
+ } else {
+ //use 16k buffers for best performance
+ //as 16k is generally the max amount of data that can be sent in a single write() call
+ directBuffers = true;
+ bufferSize = 1024 * 16;
+ buffersPerRegion = 20;
+ }
+
+ }
+
+ public Undertow build() {
+ return new Undertow(this);
+ }
+
+ @Deprecated
+ public Builder addListener(int port, String host) {
+ listeners.add(new ListenerConfig(ListenerType.HTTP, port, host, null, null));
+ return this;
+ }
+
+ public Builder addHttpListener(int port, String host) {
+ listeners.add(new ListenerConfig(ListenerType.HTTP, port, host, null, null));
+ return this;
+ }
+
+ public Builder addHttpsListener(int port, String host, KeyManager[] keyManagers, TrustManager[] trustManagers) {
+ listeners.add(new ListenerConfig(ListenerType.HTTPS, port, host, keyManagers, trustManagers));
+ return this;
+ }
+
+ public Builder addHttpsListener(int port, String host, SSLContext sslContext) {
+ listeners.add(new ListenerConfig(ListenerType.HTTPS, port, host, sslContext));
+ return this;
+ }
+
+ public Builder addAjpListener(int port, String host) {
+ listeners.add(new ListenerConfig(ListenerType.AJP, port, host, null, null));
+ return this;
+ }
+
+ @Deprecated
+ public Builder addListener(int port, String host, ListenerType listenerType) {
+ listeners.add(new ListenerConfig(listenerType, port, host, null, null));
+ return this;
+ }
+
+ public Builder setBufferSize(final int bufferSize) {
+ this.bufferSize = bufferSize;
+ return this;
+ }
+
+ public Builder setBuffersPerRegion(final int buffersPerRegion) {
+ this.buffersPerRegion = buffersPerRegion;
+ return this;
+ }
+
+ public Builder setIoThreads(final int ioThreads) {
+ this.ioThreads = ioThreads;
+ return this;
+ }
+
+ public Builder setWorkerThreads(final int workerThreads) {
+ this.workerThreads = workerThreads;
+ return this;
+ }
+
+ public Builder setDirectBuffers(final boolean directBuffers) {
+ this.directBuffers = directBuffers;
+ return this;
+ }
+
+ public Builder setHandler(final HttpHandler handler) {
+ this.handler = handler;
+ return this;
+ }
+
+ public Builder setServerOption(final Option option, final T value) {
+ serverOptions.set(option, value);
+ return this;
+ }
+
+ public Builder setSocketOption(final Option option, final T value) {
+ socketOptions.set(option, value);
+ return this;
+ }
+
+ public Builder setWorkerOption(final Option option, final T value) {
+ workerOptions.set(option, value);
+ return this;
+ }
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/UndertowLogger.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/UndertowLogger.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/UndertowLogger.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,179 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow;
+
+import io.undertow.client.ClientConnection;
+import io.undertow.server.ServerConnection;
+import org.jboss.logging.BasicLogger;
+import org.jboss.logging.Logger;
+import org.jboss.logging.annotations.Cause;
+import org.jboss.logging.annotations.LogMessage;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.sql.SQLException;
+
+/**
+ * log messages start at 5000
+ *
+ * @author Stuart Douglas
+ */
+@MessageLogger(projectCode = "UT")
+public interface UndertowLogger extends BasicLogger {
+
+ UndertowLogger ROOT_LOGGER = Logger.getMessageLogger(UndertowLogger.class, UndertowLogger.class.getPackage().getName());
+ UndertowLogger CLIENT_LOGGER = Logger.getMessageLogger(UndertowLogger.class, ClientConnection.class.getPackage().getName());
+
+ UndertowLogger REQUEST_LOGGER = Logger.getMessageLogger(UndertowLogger.class, UndertowLogger.class.getPackage().getName() + ".request");
+ UndertowLogger PROXY_REQUEST_LOGGER = Logger.getMessageLogger(UndertowLogger.class, UndertowLogger.class.getPackage().getName() + ".proxy");
+ UndertowLogger REQUEST_DUMPER_LOGGER = Logger.getMessageLogger(UndertowLogger.class, UndertowLogger.class.getPackage().getName() + ".request.dump");
+ /**
+ * Logger used for IO exceptions. Generally these should be suppressed, because they are of little interest, and it is easy for an
+ * attacker to fill up the logs by intentionally causing IO exceptions.
+ */
+ UndertowLogger REQUEST_IO_LOGGER = Logger.getMessageLogger(UndertowLogger.class, UndertowLogger.class.getPackage().getName() + ".request.io");
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5001, value = "An exception occurred processing the request")
+ void exceptionProcessingRequest(@Cause Throwable cause);
+
+ @LogMessage(level = Logger.Level.INFO)
+ @Message(id = 5002, value = "Exception reading file %s: %s")
+ void exceptionReadingFile(final File file, final IOException e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5003, value = "IOException reading from channel")
+ void ioExceptionReadingFromChannel(@Cause IOException e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5005, value = "Cannot remove uploaded file %s")
+ void cannotRemoveUploadedFile(File file);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5006, value = "Connection from %s terminated as request header was larger than %s")
+ void requestHeaderWasTooLarge(SocketAddress address, int size);
+
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 5007, value = "Request was not fully consumed")
+ void requestWasNotFullyConsumed();
+
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 5008, value = "An invalid token '%s' with value '%s' has been received.")
+ void invalidTokenReceived(final String tokenName, final String tokenValue);
+
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 5009, value = "A mandatory token %s is missing from the request.")
+ void missingAuthorizationToken(final String tokenName);
+
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 5010, value = "Verification of authentication tokens for user '%s' has failed using mechanism '%s'.")
+ void authenticationFailed(final String userName, final String mechanism);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5011, value = "Ignoring AJP request with prefix %s")
+ void ignoringAjpRequestWithPrefixCode(byte prefix);
+
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 5013, value = "An IOException occurred")
+ void ioException(@Cause IOException e);
+
+ @LogMessage(level = Logger.Level.DEBUG)
+ @Message(id = 5014, value = "Failed to parse HTTP request")
+ void failedToParseRequest(@Cause Exception e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5015, value = "Error rotating access log")
+ void errorRotatingAccessLog(@Cause IOException e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5016, value = "Error writing access log")
+ void errorWritingAccessLog(@Cause IOException e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5017, value = "Unknown variable %s")
+ void unknownVariable(String token);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5018, value = "Exception invoking close listener %s")
+ void exceptionInvokingCloseListener(ServerConnection.CloseListener l, @Cause Throwable e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5019, value = "Cannot upgrade connection")
+ void cannotUpgradeConnection(@Cause Exception e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5020, value = "Error writing JDBC log")
+ void errorWritingJDBCLog(@Cause SQLException e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5021, value = "Proxy request to %s timed out")
+ void proxyRequestTimedOut(String requestURI);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5022, value = "Exception generating error page %s")
+ void exceptionGeneratingErrorPage(@Cause Exception e, String location);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5023, value = "Exception handling request to %s")
+ void exceptionHandlingRequest(@Cause Throwable t, String requestURI);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5024, value = "Could not register resource change listener for caching resource manager, automatic invalidation of cached resource will not work")
+ void couldNotRegisterChangeListener(@Cause Exception e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5025, value = "Could not initiate SPDY connection and no HTTP fallback defined")
+ void couldNotInitiateSpdyConnection();
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5026, value = "Jetty ALPN support not found on boot class path, SPDY client will not be available.")
+ void jettyALPNNotFound();
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5027, value = "Timing out request to %s")
+ void timingOutRequest(String requestURI);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5028, value = "Proxy request to %s failed")
+ void proxyRequestFailed(String requestURI, @Cause Exception e);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5030, value = "Proxy request to %s could not resolve a backend server")
+ void proxyRequestFailedToResolveBackend(String requestURI);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5031, value = "Proxy request to %s could not connect to backend server %s")
+ void proxyFailedToConnectToBackend(String requestURI, URI uri);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5032, value = "Listener not making progress on framed channel, closing channel to prevent infinite loop")
+ void listenerNotProgressing();
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5033, value = "Failed to initiate HTTP2 connection")
+ void couldNotInitiateHttp2Connection();
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 5034, value = "Remote endpoint failed to send initial settings frame in HTTP2 connection")
+ void remoteEndpointFailedToSendInitialSettings();
+}
Index: 3rdParty_sources/undertow/io/undertow/UndertowMessages.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/UndertowMessages.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/UndertowMessages.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,341 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.channels.ClosedChannelException;
+
+import io.undertow.predicate.PredicateBuilder;
+import io.undertow.server.handlers.builder.HandlerBuilder;
+import org.jboss.logging.Messages;
+import org.jboss.logging.annotations.Cause;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageBundle;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+
+/**
+ * @author Stuart Douglas
+ */
+@MessageBundle(projectCode = "UT")
+public interface UndertowMessages {
+
+ UndertowMessages MESSAGES = Messages.getBundle(UndertowMessages.class);
+
+ @Message(id = 1, value = "Maximum concurrent requests must be larger than zero.")
+ IllegalArgumentException maximumConcurrentRequestsMustBeLargerThanZero();
+
+ @Message(id = 2, value = "The response has already been started")
+ IllegalStateException responseAlreadyStarted();
+
+ // id = 3
+
+ @Message(id = 4, value = "getResponseChannel() has already been called")
+ IllegalStateException responseChannelAlreadyProvided();
+
+ @Message(id = 5, value = "getRequestChannel() has already been called")
+ IllegalStateException requestChannelAlreadyProvided();
+
+ // id = 6
+
+ // id = 7
+
+ @Message(id = 8, value = "Handler cannot be null")
+ IllegalArgumentException handlerCannotBeNull();
+
+ @Message(id = 9, value = "Path must be specified")
+ IllegalArgumentException pathMustBeSpecified();
+
+ @Message(id = 10, value = "Session not found %s")
+ IllegalStateException sessionNotFound(final String session);
+
+ @Message(id = 11, value = "Session manager must not be null")
+ IllegalStateException sessionManagerMustNotBeNull();
+
+ @Message(id = 12, value = "Session manager was not attached to the request. Make sure that the SessionAttachmentHander is installed in the handler chain")
+ IllegalStateException sessionManagerNotFound();
+
+ @Message(id = 13, value = "Argument %s cannot be null")
+ IllegalArgumentException argumentCannotBeNull(final String argument);
+
+ @Message(id = 14, value = "close() called with data still to be flushed. Please call shutdownWrites() and then call flush() until it returns true before calling close()")
+ IOException closeCalledWithDataStillToBeFlushed();
+
+ @Message(id = 16, value = "Could not add cookie as cookie handler was not present in the handler chain")
+ IllegalStateException cookieHandlerNotPresent();
+
+ @Message(id = 17, value = "Form value is a file, use getFile() instead")
+ IllegalStateException formValueIsAFile();
+
+ @Message(id = 18, value = "Form value is a String, use getValue() instead")
+ IllegalStateException formValueIsAString();
+
+ @Message(id = 19, value = "Connection from %s terminated as request entity was larger than %s")
+ IOException requestEntityWasTooLarge(SocketAddress address, long size);
+
+ @Message(id = 20, value = "Connection terminated as request was larger than %s")
+ IOException requestEntityWasTooLarge(long size);
+
+ @Message(id = 21, value = "Session already invalidated")
+ IllegalStateException sessionAlreadyInvalidated();
+
+ @Message(id = 22, value = "The specified hash algorithm '%s' can not be found.")
+ IllegalArgumentException hashAlgorithmNotFound(String algorithmName);
+
+ @Message(id = 23, value = "An invalid Base64 token has been received.")
+ IllegalArgumentException invalidBase64Token(@Cause final IOException cause);
+
+ @Message(id = 24, value = "An invalidly formatted nonce has been received.")
+ IllegalArgumentException invalidNonceReceived();
+
+ @Message(id = 25, value = "Unexpected token '%s' within header.")
+ IllegalArgumentException unexpectedTokenInHeader(final String name);
+
+ @Message(id = 26, value = "Invalid header received.")
+ IllegalArgumentException invalidHeader();
+
+ @Message(id = 27, value = "Could not find session cookie config in the request")
+ IllegalStateException couldNotFindSessionCookieConfig();
+
+ @Message(id = 28, value = "Session %s already exists")
+ IllegalStateException sessionAlreadyExists(final String id);
+
+ @Message(id = 29, value = "Channel was closed mid chunk, if you have attempted to write chunked data you cannot shutdown the channel until after it has all been written.")
+ IOException chunkedChannelClosedMidChunk();
+
+ @Message(id = 30, value = "User %s successfully authenticated.")
+ String userAuthenticated(final String userName);
+
+ @Message(id = 31, value = "User %s has logged out.")
+ String userLoggedOut(final String userName);
+
+ @Message(id = 33, value = "Authentication type %s cannot be combined with %s")
+ IllegalStateException authTypeCannotBeCombined(String type, String existing);
+
+ @Message(id = 34, value = "Stream is closed")
+ IOException streamIsClosed();
+
+ @Message(id = 35, value = "Cannot get stream as startBlocking has not been invoked")
+ IllegalStateException startBlockingHasNotBeenCalled();
+
+ @Message(id = 36, value = "Connection terminated parsing multipart data")
+ IOException connectionTerminatedReadingMultiPartData();
+
+ @Message(id = 37, value = "Failed to parse path in HTTP request")
+ RuntimeException failedToParsePath();
+
+ @Message(id = 38, value = "Authentication failed, requested user name '%s'")
+ String authenticationFailed(final String userName);
+
+ @Message(id = 39, value = "To many query parameters, cannot have more than %s query parameters")
+ RuntimeException tooManyQueryParameters(int noParams);
+
+ @Message(id = 40, value = "To many headers, cannot have more than %s header")
+ RuntimeException tooManyHeaders(int noParams);
+
+ @Message(id = 41, value = "Channel is closed")
+ ClosedChannelException channelIsClosed();
+
+ @Message(id = 42, value = "Could not decode trailers in HTTP request")
+ IOException couldNotDecodeTrailers();
+
+ @Message(id = 43, value = "Data is already being sent. You must wait for the completion callback to be be invoked before calling send() again")
+ IllegalStateException dataAlreadyQueued();
+
+ @Message(id = 44, value = "More than one predicate with name %s. Builder class %s and %s")
+ IllegalStateException moreThanOnePredicateWithName(String name, Class extends PredicateBuilder> aClass, Class extends PredicateBuilder> existing);
+
+ @Message(id = 45, value = "Error parsing predicate string %s:%n%s")
+ IllegalArgumentException errorParsingPredicateString(String reason, String s);
+
+ @Message(id = 46, value = "The number of cookies sent exceeded the maximum of %s")
+ IllegalStateException tooManyCookies(int maxCookies);
+
+ @Message(id = 47, value = "The number of parameters exceeded the maximum of %s")
+ IllegalStateException tooManyParameters(int maxValues);
+
+ @Message(id = 48, value = "No request is currently active")
+ IllegalStateException noRequestActive();
+
+ @Message(id = 50, value = "AuthenticationMechanism Outcome is null")
+ IllegalStateException authMechanismOutcomeNull();
+
+ @Message(id = 51, value = "Not a valid IP pattern %s")
+ IllegalArgumentException notAValidIpPattern(String peer);
+
+ @Message(id = 52, value = "Session data requested when non session based authentication in use")
+ IllegalStateException noSessionData();
+
+ @Message(id = 53, value = "Listener %s already registered")
+ IllegalArgumentException listenerAlreadyRegistered(String name);
+
+ @Message(id = 54, value = "The maximum size %s for an individual file in a multipart request was exceeded")
+ IOException maxFileSizeExceeded(long maxIndividualFileSize);
+
+ @Message(id = 55, value = "Could not set attribute %s to %s as it is read only")
+ String couldNotSetAttribute(String attributeName, String newValue);
+
+ @Message(id = 56, value = "Could not parse URI template %s, exception at char %s")
+ RuntimeException couldNotParseUriTemplate(String path, int i);
+
+ @Message(id = 57, value = "Mismatched braces in attribute string %s")
+ RuntimeException mismatchedBraces(String valueString);
+
+ @Message(id = 58, value = "More than one handler with name %s. Builder class %s and %s")
+ IllegalStateException moreThanOneHandlerWithName(String name, Class extends HandlerBuilder> aClass, Class extends HandlerBuilder> existing);
+
+ @Message(id = 59, value = "Invalid syntax %s")
+ IllegalArgumentException invalidSyntax(String line);
+
+ @Message(id = 60, value = "Error parsing handler string %s:%n%s")
+ IllegalArgumentException errorParsingHandlerString(String reason, String s);
+
+ @Message(id = 61, value = "Out of band responses only allowed for 100-continue requests")
+ IllegalArgumentException outOfBandResponseOnlyAllowedFor100Continue();
+
+ @Message(id = 62, value = "AJP does not support HTTP upgrade")
+ IllegalStateException ajpDoesNotSupportHTTPUpgrade();
+
+ @Message(id = 63, value = "File system watcher already started")
+ IllegalStateException fileSystemWatcherAlreadyStarted();
+
+ @Message(id = 64, value = "File system watcher not started")
+ IllegalStateException fileSystemWatcherNotStarted();
+
+ @Message(id = 65, value = "SSL must be specified to connect to a https URL")
+ IOException sslWasNull();
+
+ @Message(id = 66, value = "Incorrect magic number for AJP packet header")
+ IOException wrongMagicNumber();
+
+ @Message(id = 67, value = "No client cert was provided")
+ SSLPeerUnverifiedException peerUnverified();
+
+ @Message(id = 68, value = "Servlet path match failed")
+ IllegalArgumentException servletPathMatchFailed();
+
+ @Message(id = 69, value = "Could not parse set cookie header %s")
+ IllegalArgumentException couldNotParseCookie(String headerValue);
+
+ @Message(id = 70, value = "method can only be called by IO thread")
+ IllegalStateException canOnlyBeCalledByIoThread();
+
+ @Message(id = 71, value = "Cannot add path template %s, matcher already contains an equivalent pattern %s")
+ IllegalStateException matcherAlreadyContainsTemplate(String templateString, String templateString1);
+
+ @Message(id = 72, value = "Failed to decode url %s to charset %s")
+ IllegalArgumentException failedToDecodeURL(String s, String enc);
+
+ @Message(id = 73, value = "Resource change listeners are not supported")
+ IllegalArgumentException resourceChangeListenerNotSupported();
+
+ @Message(id = 74, value = "Could not renegotiate SSL connection to require client certificate, as client had sent more data")
+ IllegalStateException couldNotRenegotiate();
+
+ @Message(id = 75, value = "Object was freed")
+ IllegalStateException objectWasFreed();
+
+ @Message(id = 76, value = "Handler not shutdown")
+ IllegalStateException handlerNotShutdown();
+
+ @Message(id = 77, value = "The underlying transport does not support HTTP upgrade")
+ IllegalStateException upgradeNotSupported();
+
+ @Message(id = 78, value = "Renegotiation not supported")
+ IOException renegotiationNotSupported();
+
+ @Message(id = 79, value = "Not a valid user agent pattern %s")
+ IllegalArgumentException notAValidUserAgentPattern(String userAgent);
+
+ @Message(id = 80, value = "Not a valid regular expression pattern %s")
+ IllegalArgumentException notAValidRegularExpressionPattern(String pattern);
+
+ @Message(id = 81, value = "Bad request")
+ RuntimeException badRequest();
+
+ @Message(id = 82, value = "Host %s already registered")
+ RuntimeException hostAlreadyRegistered(Object host);
+
+ @Message(id = 83, value = "Host %s has not been registered")
+ RuntimeException hostHasNotBeenRegistered(Object host);
+
+ @Message(id = 84, value = "Attempted to write additional data after the last chunk")
+ IOException extraDataWrittenAfterChunkEnd();
+
+ @Message(id = 85, value = "Could not generate unique session id")
+ RuntimeException couldNotGenerateUniqueSessionId();
+
+ @Message(id = 86, value = "SPDY needs to be provided with a heap buffer pool, for use in compressing and decompressing headers.")
+ IllegalArgumentException mustProvideHeapBuffer();
+
+ @Message(id = 87, value = "Unexpected SPDY frame type %s")
+ IOException unexpectedFrameType(int type);
+
+ @Message(id = 88, value = "SPDY control frames cannot have body content")
+ IOException controlFrameCannotHaveBodyContent();
+
+ @Message(id = 89, value = "SPDY not supported")
+ IOException spdyNotSupported();
+
+ @Message(id = 90, value = "Jetty NPN not available")
+ IOException jettyNPNNotAvailable();
+
+ @Message(id = 91, value = "Buffer has already been freed")
+ IllegalStateException bufferAlreadyFreed();
+
+ @Message(id = 92, value = "A SPDY header was too large to fit in a response buffer, if you want to support larger headers please increase the buffer size")
+ IllegalStateException headersTooLargeToFitInHeapBuffer();
+
+ @Message(id = 93, value = "A SPDY stream was reset by the remote endpoint")
+ IOException spdyStreamWasReset();
+
+ @Message(id = 94, value = "Blocking await method called from IO thread. Blocking IO must be dispatched to a worker thread or deadlocks will result.")
+ IOException awaitCalledFromIoThread();
+
+ @Message(id = 95, value = "Recursive call to flushSenders()")
+ RuntimeException recursiveCallToFlushingSenders();
+
+ @Message(id = 96, value = "More data was written to the channel than specified in the content-length")
+ IllegalStateException fixedLengthOverflow();
+
+ @Message(id = 97, value = "AJP request already in progress")
+ IllegalStateException ajpRequestAlreadyInProgress();
+
+ @Message(id = 98, value = "HTTP ping data must be 8 bytes in length")
+ IllegalArgumentException httpPingDataMustBeLength8();
+
+ @Message(id = 99, value = "Received a ping of size other than 8")
+ String invalidPingSize();
+
+ @Message(id = 100, value = "stream id must be zero for frame type %s")
+ String streamIdMustBeZeroForFrameType(int frameType);
+
+ @Message(id = 101, value = "stream id must not be zero for frame type %s")
+ String streamIdMustNotBeZeroForFrameType(int frameType);
+
+ @Message(id = 102, value = "RST_STREAM received for idle stream")
+ String rstStreamReceivedForIdleStream();
+
+ @Message(id = 103, value = "Http2 stream was reset")
+ IOException http2StreamWasReset();
+
+ @Message(id = 104, value = "Incorrect HTTP2 preface")
+ IOException incorrectHttp2Preface();
+}
Index: 3rdParty_sources/undertow/io/undertow/UndertowOptions.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/UndertowOptions.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/UndertowOptions.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,185 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow;
+
+import org.xnio.Option;
+
+/**
+ * @author Stuart Douglas
+ */
+public class UndertowOptions {
+
+ /**
+ * The maximum size in bytes of a http request header.
+ */
+ public static final Option MAX_HEADER_SIZE = Option.simple(UndertowOptions.class, "MAX_HEADER_SIZE", Integer.class);
+ /**
+ * The default size we allow for the HTTP header.
+ */
+ public static final int DEFAULT_MAX_HEADER_SIZE = 50 * 1024;
+
+ /**
+ * The default maximum size of the HTTP entity body.
+ */
+ public static final Option MAX_ENTITY_SIZE = Option.simple(UndertowOptions.class, "MAX_ENTITY_SIZE", Long.class);
+
+ /**
+ * We do not have a default upload limit
+ */
+ public static final long DEFAULT_MAX_ENTITY_SIZE = -1;
+
+ /**
+ * If we should buffer pipelined requests. Defaults to false.
+ */
+ public static final Option BUFFER_PIPELINED_DATA = Option.simple(UndertowOptions.class, "BUFFER_PIPELINED_DATA", Boolean.class);
+
+ /**
+ * The idle timeout in milliseconds after which the channel will be closed.
+ *
+ * If the underlying channel already has a read or write timeout set the smaller of the two values will be used
+ * for read/write timeouts.
+ *
+ */
+ public static final Option IDLE_TIMEOUT = Option.simple(UndertowOptions.class, "IDLE_TIMEOUT", Integer.class);
+
+ /**
+ * The maximum number of parameters that will be parsed. This is used to protect against hash vulnerabilities.
+ *
+ * This applies to both query parameters, and to POST data, but is not cumulative (i.e. you can potentially have
+ * max parameters * 2 total parameters).
+ *
+ * Defaults to 1000
+ */
+ public static final Option MAX_PARAMETERS = Option.simple(UndertowOptions.class, "MAX_PARAMETERS", Integer.class);
+
+ /**
+ * The maximum number of headers that will be parsed. This is used to protect against hash vulnerabilities.
+ *
+ * Defaults to 200
+ */
+ public static final Option MAX_HEADERS = Option.simple(UndertowOptions.class, "MAX_HEADERS", Integer.class);
+
+
+ /**
+ * The maximum number of cookies that will be parsed. This is used to protect against hash vulnerabilities.
+ *
+ * Defaults to 200
+ */
+ public static final Option MAX_COOKIES = Option.simple(UndertowOptions.class, "MAX_COOKIES", Integer.class);
+
+ /**
+ * If a request comes in with encoded / characters (i.e. %2F), will these be decoded.
+ *
+ * This can cause security problems if a front end proxy does not perform the same decoding, and as a result
+ * this is disabled by default.
+ *
+ * Defaults to false
+ *
+ * @see http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0450
+ */
+ public static final Option ALLOW_ENCODED_SLASH = Option.simple(UndertowOptions.class, "ALLOW_ENCODED_SLASH", Boolean.class);
+
+ /**
+ * If this is true then the parser will decode the URL and query parameters using the selected character encoding (UTF-8 by default). If this is false they will
+ * not be decoded. This will allow a later handler to decode them into whatever charset is desired.
+ *
+ * Defaults to true.
+ */
+ public static final Option DECODE_URL = Option.simple(UndertowOptions.class, "DECODE_URL", Boolean.class);
+
+
+ /**
+ * If this is true then the parser will decode the URL and query parameters using the selected character encoding (UTF-8 by default). If this is false they will
+ * not be decoded. This will allow a later handler to decode them into whatever charset is desired.
+ *
+ * Defaults to true.
+ */
+ public static final Option URL_CHARSET = Option.simple(UndertowOptions.class, "URL_CHARSET", String.class);
+
+ /**
+ * If this is true then a Connection: keep-alive header will be added to responses, even when it is not strictly required by
+ * the specification.
+ *
+ * Defaults to true
+ */
+ public static final Option ALWAYS_SET_KEEP_ALIVE = Option.simple(UndertowOptions.class, "ALWAYS_SET_KEEP_ALIVE", Boolean.class);
+
+ /**
+ * If this is true then a Date header will be added to all responses. The HTTP spec says this header should be added to all
+ * responses, unless the server does not have an accurate clock.
+ *
+ * Defaults to true
+ */
+ public static final Option ALWAYS_SET_DATE = Option.simple(UndertowOptions.class, "ALWAYS_SET_DATE", Boolean.class);
+
+ /**
+ * Maximum size of a buffered request, in bytes
+ *
+ * Requests are not usually buffered, the most common case is when performing SSL renegotiation for a POST request, and the post data must be fully
+ * buffered in order to perform the renegotiation.
+ *
+ * Defaults to 16384.
+ */
+ public static final Option MAX_BUFFERED_REQUEST_SIZE = Option.simple(UndertowOptions.class, "MAX_BUFFERED_REQUEST_SIZE", Integer.class);
+
+ /**
+ * If this is true then Undertow will record the request start time, to allow for request time to be logged
+ *
+ * This has a small but measurable performance impact
+ *
+ * default is false
+ */
+ public static final Option RECORD_REQUEST_START_TIME = Option.simple(UndertowOptions.class, "RECORD_REQUEST_START_TIME", Boolean.class);
+
+ /**
+ * If this is true then Undertow will allow non-escaped equals characters in unquoted cookie values.
+ *
+ * Unquoted cookie values may not contain equals characters. If present the value ends before the equals sign. The remainder of the cookie value will be dropped.
+ *
+ * default is false
+ */
+ public static final Option ALLOW_EQUALS_IN_COOKIE_VALUE = Option.simple(UndertowOptions.class, "ALLOW_EQUALS_IN_COOKIE_VALUE", Boolean.class);
+
+ /**
+ * If we should attempt to use SPDY for HTTPS connections.
+ */
+ public static final Option ENABLE_SPDY = Option.simple(UndertowOptions.class, "ENABLE_SPDY", Boolean.class);
+
+ /**
+ * If we should attempt to use HTTP2 for HTTPS connections.
+ */
+ public static final Option ENABLE_HTTP2 = Option.simple(UndertowOptions.class, "ENABLE_HTTP2", Boolean.class);
+
+ /**
+ * The size of the header table that is used in the encoder
+ */
+ public static final Option HTTP2_SETTINGS_HEADER_TABLE_SIZE = Option.simple(UndertowOptions.class, "HTTP2_SETTINGS_HEADER_TABLE_SIZE", Integer.class);
+ public static final int HTTP2_SETTINGS_HEADER_TABLE_SIZE_DEFAULT = 4096;
+
+ public static final Option HTTP2_SETTINGS_ENABLE_PUSH = Option.simple(UndertowOptions.class, "HTTP2_SETTINGS_ENABLE_PUSH", Boolean.class);
+ public static final Option HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = Option.simple(UndertowOptions.class, "HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS", Integer.class);
+
+ public static final Option HTTP2_SETTINGS_INITIAL_WINDOW_SIZE = Option.simple(UndertowOptions.class, "HTTP2_SETTINGS_INITIAL_WINDOW_SIZE", Integer.class);
+ public static final Option HTTP2_SETTINGS_MAX_FRAME_SIZE = Option.simple(UndertowOptions.class, "HTTP2_SETTINGS_MAX_FRAME_SIZE", Integer.class);
+ public static final Option HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = Option.simple(UndertowOptions.class, "HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE", Integer.class);
+
+ private UndertowOptions() {
+
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/Version.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/Version.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/Version.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow;
+
+import java.util.Properties;
+
+/**
+ * @author Tomaz Cerar (c) 2013 Red Hat Inc.
+ */
+public class Version {
+ private static final String versionString;
+ private static final String SERVER_NAME = "Undertow";
+ private static final String fullVersionString;
+
+ static {
+ String version = "Unknown";
+ try {
+ Properties props = new Properties();
+ props.load(Version.class.getResourceAsStream("version.properties"));
+ version = props.getProperty("undertow.version");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ versionString = version;
+ fullVersionString = SERVER_NAME + " - "+ versionString;
+ }
+
+ public static String getVersionString() {
+ return versionString;
+ }
+
+ public static String getFullVersionString() {
+ return fullVersionString;
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/BytesSentAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/BytesSentAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/BytesSentAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,70 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The bytes sent
+ *
+ * @author Filipe Ferraz
+ */
+public class BytesSentAttribute implements ExchangeAttribute {
+
+ public static final String BYTES_SENT_SHORT_UPPER = "%B";
+ public static final String BYTES_SENT_SHORT_LOWER = "%b";
+ public static final String BYTES_SENT = "%{BYTES_SENT}";
+
+ private final String attribute;
+
+ public BytesSentAttribute(final String attribute) {
+ this.attribute = attribute;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ if (attribute.equals(BYTES_SENT_SHORT_LOWER)) {
+ long bytesSent = exchange.getResponseContentLength();
+ return bytesSent == 0 ? "-" : Long.toString(bytesSent);
+ } else {
+ return Long.toString(exchange.getResponseContentLength());
+ }
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Bytes sent", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Bytes Sent";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(BYTES_SENT) || token.equals(BYTES_SENT_SHORT_UPPER) || token.equals(BYTES_SENT_SHORT_LOWER)) {
+ return new BytesSentAttribute(token);
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/CompositeExchangeAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/CompositeExchangeAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/CompositeExchangeAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,54 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * Exchange attribute that represents a combination of attributes that should be merged into a single string.
+ *
+ * @author Stuart Douglas
+ */
+public class CompositeExchangeAttribute implements ExchangeAttribute {
+
+ private final ExchangeAttribute[] attributes;
+
+ public CompositeExchangeAttribute(ExchangeAttribute[] attributes) {
+ ExchangeAttribute[] copy = new ExchangeAttribute[attributes.length];
+ System.arraycopy(attributes, 0, copy, 0, attributes.length);
+ this.attributes = copy;
+ }
+
+ @Override
+ public String readAttribute(HttpServerExchange exchange) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < attributes.length; ++i) {
+ final String val = attributes[i].readAttribute(exchange);
+ if(val != null) {
+ sb.append(val);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("combined", newValue);
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ConstantExchangeAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ConstantExchangeAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ConstantExchangeAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * Exchange attribute that represents a fixed value
+ *
+ * @author Stuart Douglas
+ */
+public class ConstantExchangeAttribute implements ExchangeAttribute {
+
+ private final String value;
+
+ public ConstantExchangeAttribute(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return value;
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("constant", newValue);
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/CookieAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/CookieAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/CookieAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,68 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.Cookie;
+import io.undertow.server.handlers.CookieImpl;
+
+/**
+ * A cookie
+ *
+ * @author Stuart Douglas
+ */
+public class CookieAttribute implements ExchangeAttribute {
+
+ private final String cookieName;
+
+ public CookieAttribute(final String cookieName) {
+ this.cookieName = cookieName;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ Cookie cookie = exchange.getRequestCookies().get(cookieName);
+ if (cookie == null) {
+ return null;
+ }
+ return cookie.getValue();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ exchange.setResponseCookie(new CookieImpl(cookieName, newValue));
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Cookie";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.startsWith("%{c,") && token.endsWith("}")) {
+ final String cookieName = token.substring(4, token.length() - 1);
+ return new CookieAttribute(cookieName);
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/DateTimeAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/DateTimeAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/DateTimeAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.util.Date;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.DateUtils;
+
+/**
+ * The request status code
+ *
+ * @author Stuart Douglas
+ */
+public class DateTimeAttribute implements ExchangeAttribute {
+
+ public static final String DATE_TIME_SHORT = "%t";
+ public static final String DATE_TIME = "%{DATE_TIME}";
+
+ public static final ExchangeAttribute INSTANCE = new DateTimeAttribute();
+
+ private DateTimeAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return DateUtils.toCommonLogFormat(new Date());
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Date time", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Date Time";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(DATE_TIME) || token.equals(DATE_TIME_SHORT)) {
+ return DateTimeAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,44 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * Representation of a string attribute from a HTTP server exchange.
+ *
+ *
+ * @author Stuart Douglas
+ */
+public interface ExchangeAttribute {
+
+ /**
+ * Resolve the attribute from the HTTP server exchange. This may return null if the attribute is not present.
+ * @param exchange The exchange
+ * @return The attribute
+ */
+ String readAttribute(final HttpServerExchange exchange);
+
+ /**
+ * Sets a new value for the attribute. Not all attributes are writable.
+ * @param exchange The exchange
+ * @param newValue The new value for the attribute
+ */
+ void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException;
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeBuilder.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeBuilder.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeBuilder.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,46 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+/**
+ * An interface that knows how to build an exchange attribute from a textual representation.
+ *
+ * This makes it easy to configure attributes based on a string representation
+ *
+ * @author Stuart Douglas
+ */
+public interface ExchangeAttributeBuilder {
+
+ /**
+ * The string representation of the attribute name. This is used solely for debugging / informational purposes
+ *
+ * @return The attribute name
+ */
+ String name();
+
+ /**
+ * Build the attribute from a text based representation. If the attribute does not understand this representation then
+ * it will just return null.
+ *
+ * @param token The string token
+ * @return The exchange attribute, or null
+ */
+ ExchangeAttribute build(final String token);
+
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeParser.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeParser.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeParser.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,170 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import io.undertow.UndertowLogger;
+import io.undertow.UndertowMessages;
+
+/**
+ * Attribute parser for exchange attributes. This builds an attribute from a string definition.
+ *
+ * This uses a service loader mechanism to allow additional token types to be loaded. Token definitions are loaded
+ * from the provided class loader.
+ *
+ * @author Stuart Douglas
+ * @see ExchangeAttributes#parser(ClassLoader)
+ */
+public class ExchangeAttributeParser {
+
+ private final List builders;
+ private final List wrappers;
+
+ ExchangeAttributeParser(final ClassLoader classLoader, List wrappers) {
+ this.wrappers = wrappers;
+ ServiceLoader loader = ServiceLoader.load(ExchangeAttributeBuilder.class, classLoader);
+ final List builders = new ArrayList<>();
+ for (ExchangeAttributeBuilder instance : loader) {
+ builders.add(instance);
+ }
+ this.builders = Collections.unmodifiableList(builders);
+
+ }
+
+ /**
+ * Parses the provided value string, and turns it into a list of exchange attributes.
+ *
+ * Tokens are created according to the following rules:
+ *
+ * %a - % followed by single character. %% is an escape for a literal %
+ * %{.*}a? - % plus curly braces with any amount of content inside, followed by an optional character
+ * ${.*} - $ followed by a curly braces to reference an item from the predicate context
+ *
+ * @param valueString
+ * @return
+ */
+ public ExchangeAttribute parse(final String valueString) {
+ final List attributes = new ArrayList<>();
+ int pos = 0;
+ int state = 0; //0 = literal, 1 = %, 2 = %{, 3 = $, 4 = ${
+ for (int i = 0; i < valueString.length(); ++i) {
+ char c = valueString.charAt(i);
+ switch (state) {
+ case 0: {
+ if (c == '%' || c == '$') {
+ if (pos != i) {
+ attributes.add(wrap(parseSingleToken(valueString.substring(pos, i))));
+ pos = i;
+ }
+ if (c == '%') {
+ state = 1;
+ } else {
+ state = 3;
+ }
+ }
+ break;
+ }
+ case 1: {
+ if (c == '{') {
+ state = 2;
+ } else if (c == '%') {
+ //literal percent
+ attributes.add(wrap(new ConstantExchangeAttribute("%")));
+ pos = i + 1;
+ state = 0;
+ } else {
+ attributes.add(wrap(parseSingleToken(valueString.substring(pos, i + 1))));
+ pos = i + 1;
+ state = 0;
+ }
+ break;
+ }
+ case 2: {
+ if (c == '}') {
+ attributes.add(wrap(parseSingleToken(valueString.substring(pos, i + 1))));
+ pos = i + 1;
+ state = 0;
+ }
+ break;
+ }
+ case 3: {
+ if (c == '{') {
+ state = 4;
+ } else {
+ state = 0;
+ }
+ break;
+ }
+ case 4: {
+ if (c == '}') {
+ attributes.add(wrap(parseSingleToken(valueString.substring(pos, i + 1))));
+ pos = i + 1;
+ state = 0;
+ }
+ break;
+ }
+
+ }
+ }
+ switch (state) {
+ case 0:
+ case 1:
+ case 3:{
+ if(pos != valueString.length()) {
+ attributes.add(wrap(parseSingleToken(valueString.substring(pos))));
+ }
+ break;
+ }
+ case 2:
+ case 4: {
+ throw UndertowMessages.MESSAGES.mismatchedBraces(valueString);
+ }
+ }
+ if(attributes.size() == 1) {
+ return attributes.get(0);
+ }
+ return new CompositeExchangeAttribute(attributes.toArray(new ExchangeAttribute[attributes.size()]));
+ }
+
+ public ExchangeAttribute parseSingleToken(final String token) {
+ for (final ExchangeAttributeBuilder builder : builders) {
+ ExchangeAttribute res = builder.build(token);
+ if (res != null) {
+ return res;
+ }
+ }
+ if (token.startsWith("%")) {
+ UndertowLogger.ROOT_LOGGER.unknownVariable(token);
+ }
+ return new ConstantExchangeAttribute(token);
+ }
+
+ private ExchangeAttribute wrap(ExchangeAttribute attribute) {
+ ExchangeAttribute res = attribute;
+ for(ExchangeAttributeWrapper w : wrappers) {
+ res = w.wrap(res);
+ }
+ return res;
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeWrapper.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeWrapper.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributeWrapper.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,12 @@
+package io.undertow.attribute;
+
+/**
+ * Interface that can be used to wrap an exchange attribute.
+ *
+ * @author Stuart Douglas
+ */
+public interface ExchangeAttributeWrapper {
+
+ ExchangeAttribute wrap(ExchangeAttribute attribute);
+
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributes.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributes.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ExchangeAttributes.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,134 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.HttpString;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Utility class for retrieving exchange attributes
+ *
+ * @author Stuart Douglas
+ */
+public class ExchangeAttributes {
+
+ public static ExchangeAttributeParser parser(final ClassLoader classLoader) {
+ return new ExchangeAttributeParser(classLoader, Collections.emptyList());
+ }
+
+ public static ExchangeAttributeParser parser(final ClassLoader classLoader, ExchangeAttributeWrapper ... wrappers) {
+ return new ExchangeAttributeParser(classLoader, Arrays.asList(wrappers));
+ }
+
+ public static ExchangeAttribute cookie(final String cookieName) {
+ return new CookieAttribute(cookieName);
+ }
+
+ public static ExchangeAttribute bytesSent(final String attribute) {
+ return new BytesSentAttribute(attribute);
+ }
+
+ public static ExchangeAttribute dateTime() {
+ return DateTimeAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute localIp() {
+ return LocalIPAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute localPort() {
+ return LocalPortAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute localServerName() {
+ return LocalServerNameAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute queryString() {
+ return QueryStringAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute relativePath() {
+ return RelativePathAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute remoteIp() {
+ return RemoteIPAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute remoteUser() {
+ return RemoteUserAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute requestHeader(final HttpString header) {
+ return new RequestHeaderAttribute(header);
+ }
+
+ public static ExchangeAttribute requestList() {
+ return RequestLineAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute requestMethod() {
+ return RequestMethodAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute requestProtocol() {
+ return RequestProtocolAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute requestURL() {
+ return RequestURLAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute responseCode() {
+ return ResponseCodeAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute responseHeader(final HttpString header) {
+ return new ResponseHeaderAttribute(header);
+ }
+
+ public static ExchangeAttribute threadName() {
+ return ThreadNameAttribute.INSTANCE;
+ }
+
+ public static ExchangeAttribute constant(String value) {
+ return new ConstantExchangeAttribute(value);
+ }
+
+ public static String resolve(final HttpServerExchange exchange, final ExchangeAttribute[] attributes) {
+ final StringBuilder result = new StringBuilder();
+ for (int i = 0; i < attributes.length; ++i) {
+ final String str = attributes[i].readAttribute(exchange);
+ if (str != null) {
+ result.append(str);
+ }
+ }
+ return result.toString();
+ }
+
+
+ private ExchangeAttributes() {
+
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/IdentUsernameAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/IdentUsernameAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/IdentUsernameAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The ident username, not used, included for apache access log compatibility
+ *
+ * @author Stuart Douglas
+ */
+public class IdentUsernameAttribute implements ExchangeAttribute {
+
+ public static final String IDENT_USERNAME = "%l";
+
+ public static final ExchangeAttribute INSTANCE = new IdentUsernameAttribute();
+
+ private IdentUsernameAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return null;
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Ident username", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Ident Username";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(IDENT_USERNAME)) {
+ return IdentUsernameAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/LocalIPAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/LocalIPAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/LocalIPAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.net.InetSocketAddress;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The local IP address
+ *
+ * @author Stuart Douglas
+ */
+public class LocalIPAttribute implements ExchangeAttribute {
+
+ public static final String LOCAL_IP = "%{LOCAL_IP}";
+ public static final String LOCAL_IP_SHORT = "%A";
+
+ public static final ExchangeAttribute INSTANCE = new LocalIPAttribute();
+
+ private LocalIPAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ InetSocketAddress localAddress = (InetSocketAddress) exchange.getConnection().getLocalAddress();
+ return localAddress.getAddress().getHostAddress();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Local IP", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Local IP";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(LOCAL_IP) || token.equals(LOCAL_IP_SHORT)) {
+ return LocalIPAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/LocalPortAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/LocalPortAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/LocalPortAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.net.InetSocketAddress;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The local port
+ *
+ * @author Stuart Douglas
+ */
+public class LocalPortAttribute implements ExchangeAttribute {
+
+ public static final String LOCAL_PORT_SHORT = "%p";
+ public static final String LOCAL_PORT = "%{LOCAL_PORT}";
+
+ public static final ExchangeAttribute INSTANCE = new LocalPortAttribute();
+
+ private LocalPortAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ InetSocketAddress localAddress = (InetSocketAddress) exchange.getConnection().getLocalAddress();
+ return Integer.toString(localAddress.getPort());
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Local port", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Local Port";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(LOCAL_PORT) || token.equals(LOCAL_PORT_SHORT)) {
+ return LocalPortAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/LocalServerNameAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/LocalServerNameAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/LocalServerNameAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.Headers;
+
+/**
+ * The local server name
+ *
+ * @author Stuart Douglas
+ */
+public class LocalServerNameAttribute implements ExchangeAttribute {
+
+ public static final String LOCAL_SERVER_NAME_SHORT = "%v";
+ public static final String LOCAL_SERVER_NAME = "%{LOCAL_SERVER_NAME}";
+
+ public static final ExchangeAttribute INSTANCE = new LocalServerNameAttribute();
+
+ private LocalServerNameAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getRequestHeaders().getFirst(Headers.HOST);
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Local server name", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Local server name";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(LOCAL_SERVER_NAME) || token.equals(LOCAL_SERVER_NAME_SHORT)) {
+ return LocalServerNameAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/PathParameterAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/PathParameterAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/PathParameterAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,86 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * Path parameter
+ *
+ * @author Stuart Douglas
+ */
+public class PathParameterAttribute implements ExchangeAttribute {
+
+
+ private final String parameter;
+
+ public PathParameterAttribute(String parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ Deque res = exchange.getPathParameters().get(parameter);
+ if(res == null) {
+ return null;
+ }else if(res.isEmpty()) {
+ return "";
+ } else if(res.size() ==1) {
+ return res.getFirst();
+ } else {
+ StringBuilder sb = new StringBuilder("[");
+ int i = 0;
+ for(String s : res) {
+ sb.append(s);
+ if(++i != res.size()) {
+ sb.append(", ");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ final ArrayDeque value = new ArrayDeque<>();
+ value.add(newValue);
+ exchange.getPathParameters().put(parameter, value);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Path Parameter";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.startsWith("%{p,") && token.endsWith("}")) {
+ final String qp = token.substring(4, token.length() - 1);
+ return new PathParameterAttribute(qp);
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/PredicateContextAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/PredicateContextAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/PredicateContextAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.util.Map;
+
+import io.undertow.predicate.Predicate;
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * @author Stuart Douglas
+ */
+public class PredicateContextAttribute implements ExchangeAttribute {
+
+ private final String name;
+
+ public PredicateContextAttribute(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ Map context = exchange.getAttachment(Predicate.PREDICATE_CONTEXT);
+ if (context != null) {
+ Object object = context.get(name);
+ return object == null ? null : object.toString();
+ }
+ return null;
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ Map context = exchange.getAttachment(Predicate.PREDICATE_CONTEXT);
+ if (context != null) {
+ context.put(name, newValue);
+ }
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Predicate context variable";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.startsWith("${") && token.endsWith("}") && token.length() > 3) {
+ return new PredicateContextAttribute(token.substring(2, token.length() - 1));
+ } else if (token.startsWith("$")) {
+ return new PredicateContextAttribute(token.substring(1, token.length()));
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/QueryParameterAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/QueryParameterAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/QueryParameterAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,86 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * Query parameter
+ *
+ * @author Stuart Douglas
+ */
+public class QueryParameterAttribute implements ExchangeAttribute {
+
+
+ private final String parameter;
+
+ public QueryParameterAttribute(String parameter) {
+ this.parameter = parameter;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ Deque res = exchange.getQueryParameters().get(parameter);
+ if(res == null) {
+ return null;
+ }else if(res.isEmpty()) {
+ return "";
+ } else if(res.size() ==1) {
+ return res.getFirst();
+ } else {
+ StringBuilder sb = new StringBuilder("[");
+ int i = 0;
+ for(String s : res) {
+ sb.append(s);
+ if(++i != res.size()) {
+ sb.append(", ");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ final ArrayDeque value = new ArrayDeque<>();
+ value.add(newValue);
+ exchange.getQueryParameters().put(parameter, value);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Query Parameter";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.startsWith("%{q,") && token.endsWith("}")) {
+ final String qp = token.substring(4, token.length() - 1);
+ return new QueryParameterAttribute(qp);
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/QueryStringAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/QueryStringAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/QueryStringAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,68 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The query string
+ *
+ * @author Stuart Douglas
+ */
+public class QueryStringAttribute implements ExchangeAttribute {
+
+ public static final String QUERY_STRING_SHORT = "%q";
+ public static final String QUERY_STRING = "%{QUERY_STRING}";
+
+ public static final ExchangeAttribute INSTANCE = new QueryStringAttribute();
+
+ private QueryStringAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ String qs = exchange.getQueryString();
+ if(qs.isEmpty()) {
+ return qs;
+ }
+ return '?' + qs;
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ exchange.setQueryString(newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Query String";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(QUERY_STRING) || token.equals(QUERY_STRING_SHORT)) {
+ return QueryStringAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ReadOnlyAttributeException.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ReadOnlyAttributeException.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ReadOnlyAttributeException.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,37 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.UndertowMessages;
+
+/**
+ * An exception that is thrown when an attribute is read only
+ *
+ * @author Stuart Douglas
+ */
+public class ReadOnlyAttributeException extends Exception {
+
+ public ReadOnlyAttributeException() {
+ }
+
+ public ReadOnlyAttributeException(final String attributeName, final String newValue) {
+ super(UndertowMessages.MESSAGES.couldNotSetAttribute(attributeName, newValue));
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RelativePathAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RelativePathAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RelativePathAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,76 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.QueryParameterUtils;
+
+/**
+ * The relative path
+ *
+ * @author Stuart Douglas
+ */
+public class RelativePathAttribute implements ExchangeAttribute {
+
+ public static final String RELATIVE_PATH_SHORT = "%R";
+ public static final String RELATIVE_PATH = "%{RELATIVE_PATH}";
+
+ public static final ExchangeAttribute INSTANCE = new RelativePathAttribute();
+
+ private RelativePathAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getRelativePath();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ int pos = newValue.indexOf('?');
+ if (pos == -1) {
+ exchange.setRelativePath(newValue);
+ exchange.setRequestURI(exchange.getResolvedPath() + newValue);
+ exchange.setRequestPath(exchange.getResolvedPath() + newValue);
+ } else {
+ final String path = newValue.substring(0, pos);
+ exchange.setRelativePath(path);
+ exchange.setRequestURI(exchange.getResolvedPath() + newValue);
+ exchange.setRequestPath(exchange.getResolvedPath() + newValue);
+
+ final String newQueryString = newValue.substring(pos);
+ exchange.setQueryString(newQueryString);
+ exchange.getQueryParameters().putAll(QueryParameterUtils.parseQueryString(newQueryString.substring(1), QueryParameterUtils.getQueryParamEncoding(exchange)));
+ }
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Relative Path";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ return token.equals(RELATIVE_PATH) || token.equals(RELATIVE_PATH_SHORT) ? INSTANCE : null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RemoteIPAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RemoteIPAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RemoteIPAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,68 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import java.net.InetSocketAddress;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The remote IP address
+ *
+ * @author Stuart Douglas
+ */
+public class RemoteIPAttribute implements ExchangeAttribute {
+
+ public static final String REMOTE_IP_SHORT = "%a";
+ public static final String REMOTE_HOST_NAME_SHORT = "%h";
+ public static final String REMOTE_IP = "%{REMOTE_IP}";
+
+ public static final ExchangeAttribute INSTANCE = new RemoteIPAttribute();
+
+ private RemoteIPAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ final InetSocketAddress peerAddress = (InetSocketAddress) exchange.getConnection().getPeerAddress();
+ return peerAddress.getAddress().getHostAddress();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Remote IP", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Remote IP";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(REMOTE_IP) || token.equals(REMOTE_IP_SHORT) || token.equals(REMOTE_HOST_NAME_SHORT)) {
+ return RemoteIPAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RemoteUserAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RemoteUserAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RemoteUserAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,69 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.security.api.SecurityContext;
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The remote user
+ *
+ * @author Stuart Douglas
+ */
+public class RemoteUserAttribute implements ExchangeAttribute {
+
+ public static final String REMOTE_USER_SHORT = "%u";
+ public static final String REMOTE_USER = "%{REMOTE_USER}";
+
+ public static final ExchangeAttribute INSTANCE = new RemoteUserAttribute();
+
+ private RemoteUserAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ SecurityContext sc = exchange.getSecurityContext();
+ if (sc == null || !sc.isAuthenticated()) {
+ return null;
+ }
+ return sc.getAuthenticatedAccount().getPrincipal().getName();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Remote user", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Remote user";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(REMOTE_USER) || token.equals(REMOTE_USER_SHORT)) {
+ return RemoteUserAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RequestHeaderAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RequestHeaderAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RequestHeaderAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.HttpString;
+
+/**
+ * A request header
+ *
+ * @author Stuart Douglas
+ */
+public class RequestHeaderAttribute implements ExchangeAttribute {
+
+
+ private final HttpString requestHeader;
+
+ public RequestHeaderAttribute(final HttpString requestHeader) {
+ this.requestHeader = requestHeader;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getRequestHeaders().getFirst(requestHeader);
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ exchange.getRequestHeaders().put(requestHeader, newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Request header";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.startsWith("%{i,") && token.endsWith("}")) {
+ final HttpString headerName = HttpString.tryFromString(token.substring(4, token.length() - 1));
+ return new RequestHeaderAttribute(headerName);
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RequestLineAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RequestLineAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RequestLineAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,74 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The request line
+ *
+ * @author Stuart Douglas
+ */
+public class RequestLineAttribute implements ExchangeAttribute {
+
+ public static final String REQUEST_LINE_SHORT = "%r";
+ public static final String REQUEST_LINE = "%{REQUEST_LINE}";
+
+ public static final ExchangeAttribute INSTANCE = new RequestLineAttribute();
+
+ private RequestLineAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ StringBuilder sb = new StringBuilder()
+ .append(exchange.getRequestMethod().toString())
+ .append(' ')
+ .append(exchange.getRequestURI());
+ if (!exchange.getQueryString().isEmpty()) {
+ sb.append('?');
+ sb.append(exchange.getQueryString());
+ }
+ sb.append(' ')
+ .append(exchange.getProtocol().toString()).toString();
+ return sb.toString();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Request line", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Request line";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(REQUEST_LINE) || token.equals(REQUEST_LINE_SHORT)) {
+ return RequestLineAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RequestMethodAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RequestMethodAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RequestMethodAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The request method
+ *
+ * @author Stuart Douglas
+ */
+public class RequestMethodAttribute implements ExchangeAttribute {
+
+ public static final String REQUEST_METHOD_SHORT = "%m";
+ public static final String REQUEST_METHOD = "%{METHOD}";
+
+ public static final ExchangeAttribute INSTANCE = new RequestMethodAttribute();
+
+ private RequestMethodAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getRequestMethod().toString();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Request method", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Request method";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(REQUEST_METHOD) || token.equals(REQUEST_METHOD_SHORT)) {
+ return RequestMethodAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RequestProtocolAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RequestProtocolAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RequestProtocolAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The request protocol
+ *
+ * @author Stuart Douglas
+ */
+public class RequestProtocolAttribute implements ExchangeAttribute {
+
+ public static final String REQUEST_PROTOCOL_SHORT = "%H";
+ public static final String REQUEST_PROTOCOL = "%{PROTOCOL}";
+
+ public static final ExchangeAttribute INSTANCE = new RequestProtocolAttribute();
+
+ private RequestProtocolAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getProtocol().toString();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Request protocol", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Request protocol";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(REQUEST_PROTOCOL) || token.equals(REQUEST_PROTOCOL_SHORT)) {
+ return RequestProtocolAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/RequestURLAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/RequestURLAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/RequestURLAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.QueryParameterUtils;
+
+/**
+ * The request URL
+ *
+ * @author Stuart Douglas
+ */
+public class RequestURLAttribute implements ExchangeAttribute {
+
+ public static final String REQUEST_URL_SHORT = "%U";
+ public static final String REQUEST_URL = "%{REQUEST_URL}";
+
+ public static final ExchangeAttribute INSTANCE = new RequestURLAttribute();
+
+ private RequestURLAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getRequestURI();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ int pos = newValue.indexOf('?');
+ if (pos == -1) {
+ exchange.setRelativePath(newValue);
+ exchange.setRequestURI(newValue);
+ exchange.setRequestPath(newValue);
+ exchange.setResolvedPath("");
+ } else {
+ final String path = newValue.substring(0, pos);
+ exchange.setRelativePath(path);
+ exchange.setRequestURI(path);
+ exchange.setRequestPath(path);
+ exchange.setResolvedPath("");
+ final String newQueryString = newValue.substring(pos);
+ exchange.setQueryString(newQueryString);
+ exchange.getQueryParameters().putAll(QueryParameterUtils.parseQueryString(newQueryString.substring(1), QueryParameterUtils.getQueryParamEncoding(exchange)));
+ }
+
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Request URL";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(REQUEST_URL) || token.equals(REQUEST_URL_SHORT)) {
+ return RequestURLAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ResponseCodeAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ResponseCodeAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ResponseCodeAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The request status code
+ *
+ * @author Stuart Douglas
+ */
+public class ResponseCodeAttribute implements ExchangeAttribute {
+
+ public static final String RESPONSE_CODE_SHORT = "%s";
+ public static final String RESPONSE_CODE = "%{RESPONSE_CODE}";
+
+ public static final ExchangeAttribute INSTANCE = new ResponseCodeAttribute();
+
+ private ResponseCodeAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return Integer.toString(exchange.getResponseCode());
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ exchange.setResponseCode(Integer.parseInt(newValue));
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Response code";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(RESPONSE_CODE) || token.equals(RESPONSE_CODE_SHORT)) {
+ return ResponseCodeAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ResponseHeaderAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ResponseHeaderAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ResponseHeaderAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.HttpString;
+
+/**
+ * A response header
+ *
+ * @author Stuart Douglas
+ */
+public class ResponseHeaderAttribute implements ExchangeAttribute {
+
+
+ private final HttpString responseHeader;
+
+ public ResponseHeaderAttribute(final HttpString responseHeader) {
+ this.responseHeader = responseHeader;
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return exchange.getResponseHeaders().getFirst(responseHeader);
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ exchange.getResponseHeaders().put(responseHeader, newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Response header";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.startsWith("%{o,") && token.endsWith("}")) {
+ final HttpString headerName = HttpString.tryFromString(token.substring(4, token.length() - 1));
+ return new ResponseHeaderAttribute(headerName);
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ResponseTimeAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ResponseTimeAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ResponseTimeAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The response time
+ *
+ * This will only work if {@link io.undertow.UndertowOptions#RECORD_REQUEST_START_TIME} has been set
+ */
+public class ResponseTimeAttribute implements ExchangeAttribute {
+
+ public static final String RESPONSE_TIME_MILLIS_SHORT = "%D";
+ public static final String RESPONSE_TIME_SECONDS_SHORT = "%T";
+ public static final String RESPONSE_TIME_MILLIS = "%{RESPONSE_TIME}";
+
+ private final TimeUnit timeUnit;
+
+ public ResponseTimeAttribute(TimeUnit timeUnit) {
+ this.timeUnit = timeUnit;
+ }
+
+ @Override
+ public String readAttribute(HttpServerExchange exchange) {
+ long requestStartTime = exchange.getRequestStartTime();
+ if(requestStartTime == -1) {
+ return null;
+ }
+ return String.valueOf(timeUnit.convert(System.nanoTime() - requestStartTime, TimeUnit.NANOSECONDS));
+ }
+
+ @Override
+ public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Response Time", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Response Time";
+ }
+
+ @Override
+ public ExchangeAttribute build(String token) {
+ if (token.equals(RESPONSE_TIME_MILLIS) || token.equals(RESPONSE_TIME_MILLIS_SHORT)) {
+ return new ResponseTimeAttribute(TimeUnit.MILLISECONDS);
+ }
+ if (token.equals(RESPONSE_TIME_SECONDS_SHORT)) {
+ return new ResponseTimeAttribute(TimeUnit.SECONDS);
+ }
+ return null;
+ }
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/SslCipherAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/SslCipherAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/SslCipherAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.SSLSessionInfo;
+
+/**
+ * @author Stuart Douglas
+ */
+public class SslCipherAttribute implements ExchangeAttribute {
+
+ public static final SslCipherAttribute INSTANCE = new SslCipherAttribute();
+
+ @Override
+ public String readAttribute(HttpServerExchange exchange) {
+ SSLSessionInfo ssl = exchange.getConnection().getSslSessionInfo();
+ if(ssl == null) {
+ return null;
+ }
+ return ssl.getCipherSuite();
+ }
+
+ @Override
+ public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("SSL Cipher", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "SSL Cipher";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals("%{SSL_CIPHER}")) {
+ return INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/SslClientCertAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/SslClientCertAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/SslClientCertAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,79 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.RenegotiationRequiredException;
+import io.undertow.server.SSLSessionInfo;
+import io.undertow.util.Certificates;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.security.cert.CertificateEncodingException;
+import javax.security.cert.X509Certificate;
+
+/**
+ * @author Stuart Douglas
+ */
+public class SslClientCertAttribute implements ExchangeAttribute {
+
+ public static final SslClientCertAttribute INSTANCE = new SslClientCertAttribute();
+
+ @Override
+ public String readAttribute(HttpServerExchange exchange) {
+ SSLSessionInfo ssl = exchange.getConnection().getSslSessionInfo();
+ if(ssl == null) {
+ return null;
+ }
+ X509Certificate[] certificates;
+ try {
+ certificates = ssl.getPeerCertificateChain();
+ if(certificates.length > 0) {
+ return Certificates.toPem(certificates[0]);
+ }
+ return null;
+ } catch (SSLPeerUnverifiedException e) {
+ return null;
+ } catch (CertificateEncodingException e) {
+ return null;
+ } catch (RenegotiationRequiredException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("SSL Client Cert", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "SSL Client Cert";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals("%{SSL_CLIENT_CERT}")) {
+ return INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/SslSessionIdAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/SslSessionIdAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/SslSessionIdAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.SSLSessionInfo;
+import io.undertow.util.FlexBase64;
+
+/**
+ * @author Stuart Douglas
+ */
+public class SslSessionIdAttribute implements ExchangeAttribute {
+
+ public static final SslSessionIdAttribute INSTANCE = new SslSessionIdAttribute();
+
+ @Override
+ public String readAttribute(HttpServerExchange exchange) {
+ SSLSessionInfo ssl = exchange.getConnection().getSslSessionInfo();
+ if(ssl == null || ssl.getSessionId() == null) {
+ return null;
+ }
+ return FlexBase64.encodeString(ssl.getSessionId(), false);
+ }
+
+ @Override
+ public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("SSL Session ID", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "SSL Session ID";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals("%{SSL_SESSION_ID}")) {
+ return INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/SubstituteEmptyWrapper.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/SubstituteEmptyWrapper.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/SubstituteEmptyWrapper.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,34 @@
+package io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * @author Stuart Douglas
+ */
+public class SubstituteEmptyWrapper implements ExchangeAttributeWrapper {
+
+ private final String substitute;
+
+ public SubstituteEmptyWrapper(String substitute) {
+ this.substitute = substitute;
+ }
+
+ @Override
+ public ExchangeAttribute wrap(final ExchangeAttribute attribute) {
+ return new ExchangeAttribute() {
+ @Override
+ public String readAttribute(HttpServerExchange exchange) {
+ String val = attribute.readAttribute(exchange);
+ if(val == null || val.isEmpty()) {
+ return substitute;
+ }
+ return val;
+ }
+
+ @Override
+ public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
+ attribute.writeAttribute(exchange, newValue);
+ }
+ };
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/attribute/ThreadNameAttribute.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/attribute/ThreadNameAttribute.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/attribute/ThreadNameAttribute.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.attribute;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * The thread name
+ *
+ * @author Stuart Douglas
+ */
+public class ThreadNameAttribute implements ExchangeAttribute {
+
+ public static final String THREAD_NAME_SHORT = "%I";
+ public static final String THREAD_NAME = "%{THREAD_NAME}";
+
+ public static final ExchangeAttribute INSTANCE = new ThreadNameAttribute();
+
+ private ThreadNameAttribute() {
+
+ }
+
+ @Override
+ public String readAttribute(final HttpServerExchange exchange) {
+ return Thread.currentThread().getName();
+ }
+
+ @Override
+ public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
+ throw new ReadOnlyAttributeException("Thread name", newValue);
+ }
+
+ public static final class Builder implements ExchangeAttributeBuilder {
+
+ @Override
+ public String name() {
+ return "Thread name";
+ }
+
+ @Override
+ public ExchangeAttribute build(final String token) {
+ if (token.equals(THREAD_NAME) || token.equals(THREAD_NAME_SHORT)) {
+ return ThreadNameAttribute.INSTANCE;
+ }
+ return null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/DelegatingStreamSinkChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/DelegatingStreamSinkChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/DelegatingStreamSinkChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,157 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.XnioExecutor;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+/**
+ * @author Stuart Douglas
+ */
+public abstract class DelegatingStreamSinkChannel implements StreamSinkChannel {
+
+ protected final StreamSinkChannel delegate;
+ protected final ChannelListener.SimpleSetter writeSetter = new ChannelListener.SimpleSetter<>();
+ protected final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter<>();
+
+ public DelegatingStreamSinkChannel(final StreamSinkChannel delegate) {
+ this.delegate = delegate;
+ delegate.getWriteSetter().set(ChannelListeners.delegatingChannelListener((T) this, writeSetter));
+ delegate.getCloseSetter().set(ChannelListeners.delegatingChannelListener((T) this, closeSetter));
+ }
+
+ public long transferFrom(final FileChannel src, final long position, final long count) throws IOException {
+ return delegate.transferFrom(src, position, count);
+ }
+
+ public XnioWorker getWorker() {
+ return delegate.getWorker();
+ }
+
+ public boolean isWriteResumed() {
+ return delegate.isWriteResumed();
+ }
+
+ public boolean flush() throws IOException {
+ return delegate.flush();
+ }
+
+ public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException {
+ delegate.awaitWritable(time, timeUnit);
+ }
+
+ public int write(final ByteBuffer src) throws IOException {
+ return delegate.write(src);
+ }
+
+ public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException {
+ return delegate.write(srcs, offset, length);
+ }
+
+ public void awaitWritable() throws IOException {
+ delegate.awaitWritable();
+ }
+
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ return delegate.setOption(option, value);
+ }
+
+ public ChannelListener.Setter extends StreamSinkChannel> getCloseSetter() {
+ return closeSetter;
+ }
+
+ public ChannelListener.Setter extends StreamSinkChannel> getWriteSetter() {
+ return writeSetter;
+ }
+
+ public boolean supportsOption(final Option> option) {
+ return delegate.supportsOption(option);
+ }
+
+ public final long write(final ByteBuffer[] srcs) throws IOException {
+ return write(srcs, 0, srcs.length);
+ }
+
+ public void resumeWrites() {
+ delegate.resumeWrites();
+ }
+
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ public void shutdownWrites() throws IOException {
+ delegate.shutdownWrites();
+ }
+
+ public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException {
+ return delegate.transferFrom(source, count, throughBuffer);
+ }
+
+ public XnioExecutor getWriteThread() {
+ return delegate.getWriteThread();
+ }
+
+ public void wakeupWrites() {
+ delegate.wakeupWrites();
+ }
+
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ public T getOption(final Option option) throws IOException {
+ return delegate.getOption(option);
+ }
+
+ public void suspendWrites() {
+ delegate.suspendWrites();
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return delegate.getIoThread();
+ }
+
+ @Override
+ public int writeFinal(ByteBuffer src) throws IOException {
+ return delegate.writeFinal(src);
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ return delegate.writeFinal(srcs, offset, length);
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs) throws IOException {
+ return delegate.writeFinal(srcs);
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/DelegatingStreamSourceChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/DelegatingStreamSourceChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/DelegatingStreamSourceChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,138 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.XnioExecutor;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+/**
+ * @author Stuart Douglas
+ */
+public abstract class DelegatingStreamSourceChannel implements StreamSourceChannel {
+
+ protected final ChannelListener.SimpleSetter readSetter = new ChannelListener.SimpleSetter<>();
+ protected final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter<>();
+ protected final StreamSourceChannel delegate;
+
+ public DelegatingStreamSourceChannel(final StreamSourceChannel delegate) {
+ this.delegate = delegate;
+ delegate.getReadSetter().set(ChannelListeners.delegatingChannelListener((T) this, readSetter));
+ delegate.getCloseSetter().set(ChannelListeners.delegatingChannelListener((T) this, closeSetter));
+ }
+
+ public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
+ return delegate.transferTo(position, count, target);
+ }
+
+ public void awaitReadable() throws IOException {
+ delegate.awaitReadable();
+ }
+
+ public void suspendReads() {
+ delegate.suspendReads();
+ }
+
+ public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
+ return delegate.transferTo(count, throughBuffer, target);
+ }
+
+ public XnioWorker getWorker() {
+ return delegate.getWorker();
+ }
+
+ public boolean isReadResumed() {
+ return delegate.isReadResumed();
+ }
+
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ return delegate.setOption(option, value);
+ }
+
+ public boolean supportsOption(final Option> option) {
+ return delegate.supportsOption(option);
+ }
+
+ public void shutdownReads() throws IOException {
+ delegate.shutdownReads();
+ }
+
+ public ChannelListener.Setter extends StreamSourceChannel> getReadSetter() {
+ return readSetter;
+ }
+
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ public long read(final ByteBuffer[] dsts) throws IOException {
+ return delegate.read(dsts);
+ }
+
+ public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException {
+ return delegate.read(dsts, offset, length);
+ }
+
+ public void wakeupReads() {
+ delegate.wakeupReads();
+ }
+
+ public XnioExecutor getReadThread() {
+ return delegate.getReadThread();
+ }
+
+ public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException {
+ delegate.awaitReadable(time, timeUnit);
+ }
+
+ public ChannelListener.Setter extends StreamSourceChannel> getCloseSetter() {
+ return closeSetter;
+ }
+
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ public T getOption(final Option option) throws IOException {
+ return delegate.getOption(option);
+ }
+
+ public void resumeReads() {
+ delegate.resumeReads();
+ }
+
+ public int read(final ByteBuffer dst) throws IOException {
+ return delegate.read(dst);
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return delegate.getIoThread();
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSinkChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSinkChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSinkChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,270 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import io.undertow.UndertowMessages;
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.XnioExecutor;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+import org.xnio.conduits.ConduitStreamSinkChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Stream sink channel. When this channel is considered detached it will no longer forward
+ * calls to the delegate
+ *
+ * @author Stuart Douglas
+ */
+public abstract class DetachableStreamSinkChannel implements StreamSinkChannel {
+
+
+ protected final StreamSinkChannel delegate;
+ protected ChannelListener.SimpleSetter writeSetter;
+ protected ChannelListener.SimpleSetter closeSetter;
+
+ public DetachableStreamSinkChannel(final StreamSinkChannel delegate) {
+ this.delegate = delegate;
+ }
+
+ protected abstract boolean isFinished();
+
+ @Override
+ public void suspendWrites() {
+ if (isFinished()) {
+ return;
+ }
+ delegate.suspendWrites();
+ }
+
+
+ @Override
+ public boolean isWriteResumed() {
+ if (isFinished()) {
+ return false;
+ }
+ return delegate.isWriteResumed();
+ }
+
+ @Override
+ public void shutdownWrites() throws IOException {
+ if (isFinished()) {
+ return;
+ }
+ delegate.shutdownWrites();
+ }
+
+ @Override
+ public void awaitWritable() throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ delegate.awaitWritable();
+ }
+
+ @Override
+ public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ delegate.awaitWritable(time, timeUnit);
+ }
+
+ @Override
+ public XnioExecutor getWriteThread() {
+ return delegate.getWriteThread();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return !isFinished() && delegate.isOpen();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (isFinished()) return;
+ delegate.close();
+ }
+
+ @Override
+ public boolean flush() throws IOException {
+ if (isFinished()) {
+ return true;
+ }
+ return delegate.flush();
+ }
+
+ @Override
+ public long transferFrom(final FileChannel src, final long position, final long count) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.transferFrom(src, position, count);
+ }
+
+ @Override
+ public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.transferFrom(source, count, throughBuffer);
+ }
+
+ @Override
+ public ChannelListener.Setter extends StreamSinkChannel> getWriteSetter() {
+ if (writeSetter == null) {
+ writeSetter = new ChannelListener.SimpleSetter<>();
+ if (!isFinished()) {
+ if(delegate instanceof ConduitStreamSinkChannel) {
+ ((ConduitStreamSinkChannel) delegate).setWriteListener(ChannelListeners.delegatingChannelListener(this, writeSetter));
+ } else {
+ delegate.getWriteSetter().set(ChannelListeners.delegatingChannelListener(this, writeSetter));
+ }
+ }
+ }
+ return writeSetter;
+ }
+
+ @Override
+ public ChannelListener.Setter extends StreamSinkChannel> getCloseSetter() {
+ if (closeSetter == null) {
+ closeSetter = new ChannelListener.SimpleSetter<>();
+ if (!isFinished()) {
+ delegate.getCloseSetter().set(ChannelListeners.delegatingChannelListener(this, closeSetter));
+ }
+ }
+ return closeSetter;
+ }
+
+ @Override
+ public XnioWorker getWorker() {
+ return delegate.getWorker();
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return delegate.getIoThread();
+ }
+
+ @Override
+ public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.write(srcs, offset, length);
+ }
+
+ @Override
+ public long write(final ByteBuffer[] srcs) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.write(srcs);
+ }
+
+ @Override
+ public int writeFinal(ByteBuffer src) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.writeFinal(src);
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.writeFinal(srcs, offset, length);
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.writeFinal(srcs);
+ }
+
+ @Override
+ public boolean supportsOption(final Option> option) {
+ return delegate.supportsOption(option);
+ }
+
+ @Override
+ public T getOption(final Option option) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.getOption(option);
+ }
+
+ @Override
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.setOption(option, value);
+ }
+
+ @Override
+ public int write(final ByteBuffer src) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.write(src);
+ }
+
+ @Override
+ public void resumeWrites() {
+ if (isFinished()) {
+ return;
+ }
+ delegate.resumeWrites();
+ }
+
+ @Override
+ public void wakeupWrites() {
+ if (isFinished()) {
+ return;
+ }
+ delegate.wakeupWrites();
+ }
+
+ public void responseDone() {
+ if(delegate instanceof ConduitStreamSinkChannel) {
+ ((ConduitStreamSinkChannel) delegate).setCloseListener(null);
+ ((ConduitStreamSinkChannel) delegate).setWriteListener(null);
+ } else {
+ delegate.getCloseSetter().set(null);
+ delegate.getWriteSetter().set(null);
+ }
+ if (delegate.isWriteResumed()) {
+ delegate.suspendWrites();
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSourceChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSourceChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSourceChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,214 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.XnioExecutor;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+import org.xnio.conduits.ConduitStreamSourceChannel;
+
+import io.undertow.UndertowMessages;
+
+/**
+ * A stream source channel that can be marked as detached. Once this is marked as detached then
+ * calls will no longer be forwarded to the delegate.
+ *
+ * @author Stuart Douglas
+ */
+public abstract class DetachableStreamSourceChannel implements StreamSourceChannel{
+
+ protected final StreamSourceChannel delegate;
+
+ protected ChannelListener.SimpleSetter readSetter;
+ protected ChannelListener.SimpleSetter closeSetter;
+
+ public DetachableStreamSourceChannel(final StreamSourceChannel delegate) {
+ this.delegate = delegate;
+ }
+
+ protected abstract boolean isFinished();
+
+ @Override
+ public void resumeReads() {
+ if (isFinished()) {
+ return;
+ }
+ delegate.resumeReads();
+ }
+
+ public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
+ if (isFinished()) {
+ return -1;
+ }
+ return delegate.transferTo(position, count, target);
+ }
+
+ public void awaitReadable() throws IOException {
+ if (isFinished()) {
+ return;
+ }
+ delegate.awaitReadable();
+ }
+
+ public void suspendReads() {
+ if (isFinished()) {
+ return;
+ }
+ delegate.suspendReads();
+ }
+
+ public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
+ if (isFinished()) {
+ return -1;
+ }
+ return delegate.transferTo(count, throughBuffer, target);
+ }
+
+ public XnioWorker getWorker() {
+ return delegate.getWorker();
+ }
+
+ public boolean isReadResumed() {
+ if (isFinished()) {
+ return false;
+ }
+ return delegate.isReadResumed();
+ }
+
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ return delegate.setOption(option, value);
+ }
+
+ public boolean supportsOption(final Option> option) {
+ return delegate.supportsOption(option);
+ }
+
+ public void shutdownReads() throws IOException {
+ if (isFinished()) {
+ return;
+ }
+ delegate.shutdownReads();
+ }
+
+ public ChannelListener.Setter extends StreamSourceChannel> getReadSetter() {
+ if (readSetter == null) {
+ readSetter = new ChannelListener.SimpleSetter<>();
+ if (!isFinished()) {
+ if(delegate instanceof ConduitStreamSourceChannel) {
+ ((ConduitStreamSourceChannel)delegate).setReadListener(ChannelListeners.delegatingChannelListener(this, readSetter));
+ } else {
+ delegate.getReadSetter().set(ChannelListeners.delegatingChannelListener(this, readSetter));
+ }
+ }
+ }
+ return readSetter;
+ }
+
+ public boolean isOpen() {
+ if (isFinished()) {
+ return false;
+ }
+ return delegate.isOpen();
+ }
+
+ public long read(final ByteBuffer[] dsts) throws IOException {
+ if (isFinished()) {
+ return -1;
+ }
+ return delegate.read(dsts);
+ }
+
+ public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException {
+ if (isFinished()) {
+ return -1;
+ }
+ return delegate.read(dsts, offset, length);
+ }
+
+ public void wakeupReads() {
+ if (isFinished()) {
+ return;
+ }
+ delegate.wakeupReads();
+ }
+
+ public XnioExecutor getReadThread() {
+ return delegate.getReadThread();
+ }
+
+ public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.channelIsClosed();
+ }
+ delegate.awaitReadable(time, timeUnit);
+ }
+
+ public ChannelListener.Setter extends StreamSourceChannel> getCloseSetter() {
+ if (closeSetter == null) {
+ closeSetter = new ChannelListener.SimpleSetter<>();
+ if (!isFinished()) {
+ if(delegate instanceof ConduitStreamSourceChannel) {
+ ((ConduitStreamSourceChannel)delegate).setCloseListener(ChannelListeners.delegatingChannelListener(this, closeSetter));
+ } else {
+ delegate.getCloseSetter().set(ChannelListeners.delegatingChannelListener(this, closeSetter));
+ }
+ }
+ }
+ return closeSetter;
+ }
+
+ public void close() throws IOException {
+ if (isFinished()) {
+ return;
+ }
+ delegate.close();
+ }
+
+ public T getOption(final Option option) throws IOException {
+ if (isFinished()) {
+ throw UndertowMessages.MESSAGES.streamIsClosed();
+ }
+ return delegate.getOption(option);
+ }
+
+ public int read(final ByteBuffer dst) throws IOException {
+ if (isFinished()) {
+ return -1;
+ }
+ return delegate.read(dst);
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return delegate.getIoThread();
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/GatedStreamSinkChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/GatedStreamSinkChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/GatedStreamSinkChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,297 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.XnioExecutor;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+import static org.xnio.Bits.allAreClear;
+import static org.xnio.Bits.allAreSet;
+import static org.xnio.Bits.anyAreClear;
+import static org.xnio.Bits.anyAreSet;
+
+/**
+ * A 'gated' stream sink channel.
+ *
+ * This channel has a gate which starts of closed. When the gate is closed writes will return 0. When the gate is opened
+ * writes will resume as normal.
+ *
+ * @author David M. Lloyd
+ */
+public final class GatedStreamSinkChannel implements StreamSinkChannel {
+ private final StreamSinkChannel delegate;
+ private final ChannelListener.SimpleSetter writeSetter = new ChannelListener.SimpleSetter<>();
+ private final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter<>();
+
+ /**
+ * Construct a new instance.
+ *
+ * @param delegate the channel to wrap
+ */
+ public GatedStreamSinkChannel(final StreamSinkChannel delegate) {
+ this.delegate = delegate;
+ }
+
+ @SuppressWarnings("unused")
+ private int state;
+
+ private static final int FLAG_GATE_OPEN = 1 << 0;
+ private static final int FLAG_WRITES_RESUMED = 1 << 1;
+ private static final int FLAG_CLOSE_REQUESTED = 1 << 2;
+ private static final int FLAG_CLOSED = 1 << 3;
+
+ /**
+ * Open the gate and allow data to flow. Once opened, the gate cannot be closed other than closing the channel.
+ *
+ * If the shutdownWrites() or close() method has already been called this will result it in being invoked on the
+ * delegate.
+ */
+ public void openGate() throws IOException {
+ int val = state;
+ if (allAreSet(val, FLAG_GATE_OPEN)) {
+ return;
+ }
+ state |= FLAG_GATE_OPEN;
+ if (allAreSet(val, FLAG_CLOSED)) {
+ delegate.close();
+ } else {
+ if (allAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ delegate.shutdownWrites();
+ }
+ if (allAreSet(val, FLAG_WRITES_RESUMED)) {
+ delegate.wakeupWrites();
+ }
+ }
+ }
+
+ public boolean isGateOpen() {
+ return allAreSet(state, FLAG_GATE_OPEN);
+ }
+
+ public XnioWorker getWorker() {
+ return delegate.getWorker();
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return delegate.getIoThread();
+ }
+
+ public XnioExecutor getWriteThread() {
+ return delegate.getWriteThread();
+ }
+
+ public ChannelListener.Setter extends StreamSinkChannel> getWriteSetter() {
+ return writeSetter;
+ }
+
+ public ChannelListener.Setter extends StreamSinkChannel> getCloseSetter() {
+ return closeSetter;
+ }
+
+ @Override
+ public int writeFinal(ByteBuffer src) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.writeFinal(src);
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.writeFinal(srcs, offset, length);
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.writeFinal(srcs);
+ }
+
+ public int write(final ByteBuffer src) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.write(src);
+ }
+
+ public long write(final ByteBuffer[] srcs) throws IOException {
+ return write(srcs, 0, srcs.length);
+ }
+
+ public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.write(srcs, offset, length);
+ }
+
+ private boolean handleGate() throws ClosedChannelException {
+ int val = state;
+ if (anyAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ throw new ClosedChannelException();
+ }
+ if (anyAreClear(val, FLAG_GATE_OPEN)) {
+ return true;
+ }
+ return false;
+ }
+
+ public long transferFrom(final FileChannel src, final long position, final long count) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.transferFrom(src, position, count);
+ }
+
+ public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException {
+ if (handleGate()) {
+ return 0;
+ }
+ return delegate.transferFrom(source, count, throughBuffer);
+ }
+
+ public boolean flush() throws IOException {
+ if (anyAreClear(state, FLAG_GATE_OPEN)) {
+ return false;
+ }
+ if (anyAreSet(state, FLAG_CLOSED)) {
+ throw new ClosedChannelException();
+ }
+ if (anyAreSet(state, FLAG_CLOSE_REQUESTED)) {
+ boolean result = delegate.flush();
+ if (result) {
+ state |= FLAG_CLOSED;
+ }
+ return result;
+ }
+ return delegate.flush();
+ }
+
+ public void suspendWrites() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.suspendWrites();
+ } else {
+ state &= ~FLAG_WRITES_RESUMED;
+ }
+ }
+
+ public void resumeWrites() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.resumeWrites();
+ } else {
+ state |= FLAG_WRITES_RESUMED;
+ }
+ }
+
+ public boolean isWriteResumed() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ return delegate.isWriteResumed();
+ } else {
+ return anyAreSet(state, FLAG_WRITES_RESUMED);
+ }
+ }
+
+ public void wakeupWrites() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.wakeupWrites();
+ } else {
+ state |= FLAG_WRITES_RESUMED;
+ getIoThread().execute(new Runnable() {
+ @Override
+ public void run() {
+ ChannelListeners.invokeChannelListener(GatedStreamSinkChannel.this, writeSetter.get());
+ }
+ });
+ }
+ }
+
+ public void shutdownWrites() throws IOException {
+ state |= FLAG_CLOSE_REQUESTED;
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.shutdownWrites();
+ }
+ }
+
+ public void close() throws IOException {
+ if (allAreSet(state, FLAG_CLOSED)) {
+ return;
+ }
+ state |= FLAG_CLOSED;
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.close();
+ }
+ }
+
+ public void awaitWritable() throws IOException {
+ if (allAreClear(state, FLAG_GATE_OPEN)) {
+ throw new IllegalStateException();//we don't allow this, as it results in thread safety issues
+ }
+ delegate.awaitWritable();
+ }
+
+ public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException {
+ if (allAreClear(state, FLAG_GATE_OPEN)) {
+ throw new IllegalStateException();//we don't allow this, as it results in thread safety issues
+ }
+ delegate.awaitWritable(time, timeUnit);
+ }
+
+ public boolean isOpen() {
+ return allAreClear(state, FLAG_CLOSED);
+ }
+
+ public boolean supportsOption(final Option> option) {
+ return false;
+ }
+
+ public T getOption(final Option option) throws IOException {
+ return null;
+ }
+
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ return null;
+ }
+
+ /**
+ * Get the underlying channel if the gate is open, else return this channel.
+ *
+ * @return the underlying channel, or this channel if the gate is not open
+ */
+ public StreamSinkChannel getChannel() {
+ return allAreSet(state, FLAG_GATE_OPEN) ? delegate : this;
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/GatedStreamSourceChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/GatedStreamSourceChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/GatedStreamSourceChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,284 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.XnioExecutor;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+import static org.xnio.Bits.allAreClear;
+import static org.xnio.Bits.allAreSet;
+import static org.xnio.Bits.anyAreClear;
+import static org.xnio.Bits.anyAreSet;
+
+/**
+ * A 'gated' stream source channel.
+ *
+ * This channel has a gate which starts of closed. When the gate is closed reads will return 0. When the gate is opened
+ * reads will resume as normal.
+ *
+ * @author David M. Lloyd
+ */
+public final class GatedStreamSourceChannel implements StreamSourceChannel {
+ private final StreamSourceChannel delegate;
+ private final ChannelListener.SimpleSetter readSetter = new ChannelListener.SimpleSetter<>();
+ private final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter<>();
+
+ /**
+ * Construct a new instance.
+ *
+ * @param delegate the channel to wrap
+ */
+ public GatedStreamSourceChannel(final StreamSourceChannel delegate) {
+ this.delegate = delegate;
+ }
+
+ @SuppressWarnings("unused")
+ private int state;
+
+ private static final int FLAG_GATE_OPEN = 1 << 0;
+ private static final int FLAG_READS_RESUMED = 1 << 1;
+ private static final int FLAG_CLOSE_REQUESTED = 1 << 2;
+ private static final int FLAG_CLOSED = 1 << 3;
+
+ /**
+ * Open the gate and allow data to flow. Once opened, the gate cannot be closed other than closing the channel.
+ *
+ * If the shutdownReads() or close() method has already been called this will result it in being invoked on the
+ * delegate.
+ */
+ public void openGate() throws IOException {
+ int val = state;
+ if (allAreSet(val, FLAG_GATE_OPEN)) {
+ return;
+ }
+ state |= FLAG_GATE_OPEN;
+ if (allAreSet(val, FLAG_CLOSED)) {
+ delegate.close();
+ } else {
+ if (allAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ delegate.shutdownReads();
+ }
+ if (allAreSet(val, FLAG_READS_RESUMED)) {
+ delegate.wakeupReads();
+ }
+ }
+ }
+
+ public boolean isGateOpen() {
+ return allAreSet(state, FLAG_GATE_OPEN);
+ }
+
+ public XnioWorker getWorker() {
+ return delegate.getWorker();
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return delegate.getIoThread();
+ }
+
+ @Override
+ public long transferTo(long position, long count, FileChannel target) throws IOException {
+ int val = state;
+ if (anyAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ return -1;
+ }
+ if (anyAreClear(val, FLAG_GATE_OPEN)) {
+ return 0;
+ }
+ return delegate.transferTo(position, count, target);
+ }
+
+ @Override
+ public long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel target) throws IOException {
+ int val = state;
+ if (anyAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ return -1;
+ }
+ if (anyAreClear(val, FLAG_GATE_OPEN)) {
+ return 0;
+ }
+ return delegate.transferTo(count, throughBuffer, target);
+ }
+
+ @Override
+ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+ int val = state;
+ if (anyAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ return -1;
+ }
+ if (anyAreClear(val, FLAG_GATE_OPEN)) {
+ return 0;
+ }
+ return delegate.read(dsts, offset, length);
+ }
+
+ @Override
+ public long read(ByteBuffer[] dsts) throws IOException {
+ int val = state;
+ if (anyAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ return -1;
+ }
+ if (anyAreClear(val, FLAG_GATE_OPEN)) {
+ return 0;
+ }
+ return delegate.read(dsts);
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ int val = state;
+ if (anyAreSet(val, FLAG_CLOSE_REQUESTED)) {
+ return -1;
+ }
+ if (anyAreClear(val, FLAG_GATE_OPEN)) {
+ return 0;
+ }
+ return delegate.read(dst);
+ }
+ @Override
+ public void suspendReads() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.suspendReads();
+ } else {
+ state &= ~FLAG_READS_RESUMED;
+ }
+ }
+
+ @Override
+ public void resumeReads() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.resumeReads();
+ } else {
+ state |= FLAG_READS_RESUMED;
+ }
+ }
+
+ @Override
+ public boolean isReadResumed() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ return delegate.isReadResumed();
+ } else {
+ return anyAreSet(state, FLAG_READS_RESUMED);
+ }
+ }
+
+ @Override
+ public void wakeupReads() {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.resumeReads();
+ } else {
+ state |= FLAG_READS_RESUMED;
+ getIoThread().execute(new Runnable() {
+ @Override
+ public void run() {
+ ChannelListeners.invokeChannelListener(GatedStreamSourceChannel.this, readSetter.get());
+ }
+ });
+ }
+ }
+
+ @Override
+ public void shutdownReads() throws IOException {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.shutdownReads();
+ } else {
+ state |= FLAG_CLOSE_REQUESTED;
+ }
+ }
+
+ @Override
+ public void awaitReadable() throws IOException {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.awaitReadable();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public void awaitReadable(long time, TimeUnit timeUnit) throws IOException {
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.awaitReadable(time, timeUnit);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public XnioExecutor getReadThread() {
+ return delegate.getIoThread();
+ }
+
+ @Override
+ public ChannelListener.Setter extends StreamSourceChannel> getReadSetter() {
+ return readSetter;
+ }
+
+ public ChannelListener.Setter extends StreamSourceChannel> getCloseSetter() {
+ return closeSetter;
+ }
+
+ public void close() throws IOException {
+ if (allAreSet(state, FLAG_CLOSED)) {
+ return;
+ }
+ state |= FLAG_CLOSED;
+ if (anyAreSet(state, FLAG_GATE_OPEN)) {
+ delegate.close();
+ }
+ }
+
+ public boolean isOpen() {
+ return allAreClear(state, FLAG_CLOSED);
+ }
+
+ public boolean supportsOption(final Option> option) {
+ return false;
+ }
+
+ public T getOption(final Option option) throws IOException {
+ return null;
+ }
+
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ return null;
+ }
+
+ /**
+ * Get the underlying channel if the gate is open, else return this channel.
+ *
+ * @return the underlying channel, or this channel if the gate is not open
+ */
+ public StreamSourceChannel getChannel() {
+ return allAreSet(state, FLAG_GATE_OPEN) ? delegate : this;
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/ReadTimeoutStreamSourceChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/ReadTimeoutStreamSourceChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/ReadTimeoutStreamSourceChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+import io.undertow.UndertowLogger;
+import org.xnio.ChannelListeners;
+import org.xnio.IoUtils;
+import org.xnio.Option;
+import org.xnio.Options;
+import org.xnio.XnioExecutor;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+/**
+ * Wrapper for read timeout. This should always be the first wrapper applied to the underlying channel.
+ *
+ * @author Stuart Douglas
+ * @see org.xnio.Options#READ_TIMEOUT
+ */
+public final class ReadTimeoutStreamSourceChannel extends DelegatingStreamSourceChannel {
+
+ private int readTimeout;
+ private XnioExecutor.Key handle;
+
+ private final Runnable timeoutCommand = new Runnable() {
+ @Override
+ public void run() {
+ UndertowLogger.REQUEST_LOGGER.tracef("Timing out channel %s due to inactivity");
+ try {
+ if (delegate.isReadResumed()) {
+ ChannelListeners.invokeChannelListener(ReadTimeoutStreamSourceChannel.this, readSetter.get());
+ }
+ } finally {
+ IoUtils.safeClose(delegate);
+ }
+ }
+ };
+
+ /**
+ * @param delegate The underlying channel
+ * @param readTimeout The read timeout, in milliseconds
+ */
+ public ReadTimeoutStreamSourceChannel(final StreamSourceChannel delegate) {
+ super(delegate);
+ try {
+ Integer timeout = delegate.getOption(Options.READ_TIMEOUT);
+ if (timeout != null) {
+ this.readTimeout = timeout;
+ } else {
+ this.readTimeout = 0;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void handleReadTimeout(final long ret) {
+ if (readTimeout > 0) {
+ if (ret == 0 && handle == null) {
+ handle = delegate.getReadThread().executeAfter(timeoutCommand, readTimeout, TimeUnit.MILLISECONDS);
+ } else if (ret > 0 && handle != null) {
+ handle.remove();
+ }
+ }
+ }
+
+ @Override
+ public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
+ long ret = delegate.transferTo(position, count, target);
+ handleReadTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
+ long ret = delegate.transferTo(count, throughBuffer, target);
+ handleReadTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException {
+ long ret = delegate.read(dsts, offset, length);
+ handleReadTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long read(final ByteBuffer[] dsts) throws IOException {
+ long ret = delegate.read(dsts);
+ handleReadTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public int read(final ByteBuffer dst) throws IOException {
+ int ret = delegate.read(dst);
+ handleReadTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ T ret = super.setOption(option, value);
+ if (option == Options.READ_TIMEOUT) {
+ readTimeout = (Integer) value;
+ if (handle != null) {
+ handle.remove();
+ if (readTimeout > 0) {
+ getReadThread().executeAfter(timeoutCommand, readTimeout, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+ return ret;
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/channels/WriteTimeoutStreamSinkChannel.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/channels/WriteTimeoutStreamSinkChannel.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/channels/WriteTimeoutStreamSinkChannel.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,151 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.TimeUnit;
+
+import io.undertow.UndertowLogger;
+import org.xnio.ChannelListeners;
+import org.xnio.IoUtils;
+import org.xnio.Option;
+import org.xnio.Options;
+import org.xnio.XnioExecutor;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+/**
+ * Wrapper for write timeout. This should always be the first wrapper applied to the underlying channel.
+ *
+ *
+ * @author Stuart Douglas
+ * @see org.xnio.Options#WRITE_TIMEOUT
+ */
+public final class WriteTimeoutStreamSinkChannel extends DelegatingStreamSinkChannel {
+
+ private int writeTimeout;
+ private XnioExecutor.Key handle;
+
+ private final Runnable timeoutCommand = new Runnable() {
+ @Override
+ public void run() {
+ UndertowLogger.REQUEST_LOGGER.tracef("Timing out channel %s due to inactivity");
+ try {
+ if (delegate.isWriteResumed()) {
+ ChannelListeners.invokeChannelListener(WriteTimeoutStreamSinkChannel.this, writeSetter.get());
+ }
+ } finally {
+ IoUtils.safeClose(delegate);
+ }
+ }
+ };
+
+ /**
+ * @param delegate The underlying channel
+ */
+ public WriteTimeoutStreamSinkChannel(final StreamSinkChannel delegate) {
+ super(delegate);
+ try {
+ Integer timeout = delegate.getOption(Options.WRITE_TIMEOUT);
+ if (timeout != null) {
+ this.writeTimeout = timeout;
+ } else {
+ this.writeTimeout = 0;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void handleWriteTimeout(final long ret) {
+ if (writeTimeout > 0) {
+ if (ret == 0 && handle == null) {
+ handle = delegate.getWriteThread().executeAfter(timeoutCommand, writeTimeout, TimeUnit.MILLISECONDS);
+ } else if (ret > 0 && handle != null) {
+ handle.remove();
+ }
+ }
+ }
+
+ @Override
+ public int write(final ByteBuffer src) throws IOException {
+ int ret = delegate.write(src);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException {
+ long ret = delegate.write(srcs, offset, length);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public int writeFinal(ByteBuffer src) throws IOException {
+ int ret = delegate.writeFinal(src);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ long ret = delegate.writeFinal(srcs, offset, length);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long writeFinal(ByteBuffer[] srcs) throws IOException {
+ long ret = delegate.writeFinal(srcs);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long transferFrom(final FileChannel src, final long position, final long count) throws IOException {
+ long ret = delegate.transferFrom(src, position, count);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException {
+ long ret = delegate.transferFrom(source, count, throughBuffer);
+ handleWriteTimeout(ret);
+ return ret;
+ }
+
+ @Override
+ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
+ T ret = super.setOption(option, value);
+ if (option == Options.WRITE_TIMEOUT) {
+ writeTimeout = (Integer) value;
+ if (handle != null) {
+ handle.remove();
+ if(writeTimeout > 0) {
+ getWriteThread().executeAfter(timeoutCommand, writeTimeout, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+ return ret;
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ClientCallback.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ClientCallback.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ClientCallback.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import java.io.IOException;
+
+/**
+ * @author Emanuel Muckenhuber
+ */
+public interface ClientCallback {
+
+ /**
+ * Invoked when an operation completed.
+ *
+ * @param result the operation result
+ */
+ void completed(T result);
+
+ /**
+ * Invoked when the operation failed.
+ *
+ * @param e the exception
+ */
+ void failed(IOException e);
+
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ClientConnection.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ClientConnection.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ClientConnection.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,91 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import org.xnio.ChannelListener;
+import org.xnio.Option;
+import org.xnio.Pool;
+import org.xnio.StreamConnection;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+
+/**
+ * A client connection. This can be used to send requests, or to upgrade the connection.
+ *
+ * In general these objects are not thread safe, they should only be used by the IO thread
+ * that is responsible for the connection. As a result this client does not provide a mechanism
+ * to perform blocking IO, it is designed for async operation only.
+ *
+ * @author Stuart Douglas
+ */
+public interface ClientConnection extends Channel {
+
+ /**
+ * Sends a client request. The request object should not be modified after it has been submitted to the connection.
+ *
+ * Request objects can be queued. Once the request is in a state that it is ready to be sent the {@code clientCallback}
+ * is invoked to provide the caller with the {@link ClientExchange}
+ *
+ * Note that the request header may not be written out until after the callback has been invoked. This allows the
+ * client to write out a header with a gathering write if the request contains content.
+ *
+ * @param request The request to send.
+ * @return The resulting client exchange, that can be used to send the request body and read the response
+ */
+ void sendRequest(final ClientRequest request, final ClientCallback clientCallback);
+
+ /**
+ * Upgrade the connection, if the underlying protocol supports it. This should only be called after an upgrade request
+ * has been submitted and the target server has accepted the upgrade.
+ *
+ * @return The resulting StreamConnection
+ */
+ StreamConnection performUpgrade() throws IOException;
+
+ Pool getBufferPool();
+
+ SocketAddress getPeerAddress();
+
+ A getPeerAddress(Class type);
+
+ ChannelListener.Setter extends ClientConnection> getCloseSetter();
+
+ SocketAddress getLocalAddress();
+
+ A getLocalAddress(Class type);
+
+ XnioWorker getWorker();
+
+ XnioIoThread getIoThread();
+
+ boolean isOpen();
+
+ boolean supportsOption(Option> option);
+
+ T getOption(Option option) throws IOException;
+
+ T setOption(Option option, T value) throws IllegalArgumentException, IOException;
+
+ boolean isUpgraded();
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ClientExchange.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ClientExchange.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ClientExchange.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import io.undertow.util.Attachable;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+/**
+ * @author Stuart Douglas
+ */
+public interface ClientExchange extends Attachable {
+
+ void setResponseListener(final ClientCallback responseListener);
+
+ void setContinueHandler(final ContinueNotification continueHandler);
+
+ /**
+ * Returns the request channel that can be used to send data to the server.
+ *
+ * @return The request channel
+ */
+ StreamSinkChannel getRequestChannel();
+
+ /**
+ * Returns the response channel that can be used to read data from the target server.
+ *
+ * @return The response channel
+ */
+ StreamSourceChannel getResponseChannel();
+
+ ClientRequest getRequest();
+
+ /**
+ *
+ * @return The client response, or null if it has not been received yet
+ */
+ ClientResponse getResponse();
+
+ /**
+ *
+ * @return the result of a HTTP 100-continue response
+ */
+ ClientResponse getContinueResponse();
+
+ /**
+ *
+ * @return The underlying connection
+ */
+ ClientConnection getConnection();
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ClientProvider.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ClientProvider.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ClientProvider.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import org.xnio.OptionMap;
+import org.xnio.Pool;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.ssl.XnioSsl;
+
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Set;
+
+/**
+ * A client connection provider. This allows the difference between various connection
+ * providers to be abstracted away (HTTP, AJP etc).
+ *
+ * @author Stuart Douglas
+ */
+public interface ClientProvider {
+
+ Set handlesSchemes();
+
+ void connect(final ClientCallback listener, final URI uri, final XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options);
+
+ void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options);
+
+ void connect(final ClientCallback listener, final URI uri, final XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options);
+
+ void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options);
+
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ClientRequest.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ClientRequest.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ClientRequest.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import io.undertow.util.AbstractAttachable;
+import io.undertow.util.HeaderMap;
+import io.undertow.util.HttpString;
+import io.undertow.util.Methods;
+import io.undertow.util.Protocols;
+
+/**
+ * A client request. This class should not be modified once it has been submitted to the {@link ClientConnection}.
+ *
+ * This class only represents the HTTP header, it does not represent an entity body. If the request needs an entity
+ * body then this must be specified by either setting a Content-Length or Transfer-Encoding header, otherwise
+ * the client will assume that the body is empty.
+ *
+ * @author Stuart Douglas
+ */
+public final class ClientRequest extends AbstractAttachable {
+
+ private final HeaderMap requestHeaders = new HeaderMap();
+ private String path = "/";
+ private HttpString method = Methods.GET;
+ private HttpString protocol = Protocols.HTTP_1_1;
+
+ public HeaderMap getRequestHeaders() {
+ return requestHeaders;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public HttpString getMethod() {
+ return method;
+ }
+
+ public HttpString getProtocol() {
+ return protocol;
+ }
+
+ public ClientRequest setPath(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public ClientRequest setMethod(HttpString method) {
+ this.method = method;
+ return this;
+ }
+
+ public ClientRequest setProtocol(HttpString protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ClientResponse.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ClientResponse.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ClientResponse.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import io.undertow.util.AbstractAttachable;
+import io.undertow.util.HeaderMap;
+import io.undertow.util.HttpString;
+
+/**
+ * A client response. This just contains the parsed response header, the response body
+ * can be read from the {@link ClientExchange}.
+ *
+ * @author Stuart Douglas
+ */
+public final class ClientResponse extends AbstractAttachable {
+
+ private final HeaderMap responseHeaders;
+ private final int responseCode;
+ private final String status;
+ private final HttpString protocol;
+
+ public ClientResponse(int responseCode, String status, HttpString protocol) {
+ this.responseCode = responseCode;
+ this.status = status;
+ this.protocol = protocol;
+ this.responseHeaders = new HeaderMap();
+ }
+
+ public ClientResponse(int responseCode, String status, HttpString protocol, HeaderMap headers) {
+ this.responseCode = responseCode;
+ this.status = status;
+ this.protocol = protocol;
+ this.responseHeaders = headers;
+ }
+ public HeaderMap getResponseHeaders() {
+ return responseHeaders;
+ }
+
+ public HttpString getProtocol() {
+ return protocol;
+ }
+
+ public int getResponseCode() {
+ return responseCode;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ContinueNotification.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ContinueNotification.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ContinueNotification.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,30 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+/**
+ * Callback class that provides a notification of a HTTP 100 Continue response in the client.
+ *
+ * @author Stuart Douglas
+ */
+public interface ContinueNotification {
+
+ void handleContinue(ClientExchange exchange);
+
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ProxiedRequestAttachments.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ProxiedRequestAttachments.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ProxiedRequestAttachments.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import io.undertow.util.AttachmentKey;
+
+/**
+ * Additional attachments that are specific to requests that are being proxied from one server to another
+ *
+ * @author Stuart Douglas
+ */
+public class ProxiedRequestAttachments {
+
+ public static final AttachmentKey REMOTE_ADDRESS = AttachmentKey.create(String.class);
+ public static final AttachmentKey REMOTE_HOST = AttachmentKey.create(String.class);
+ public static final AttachmentKey SERVER_NAME = AttachmentKey.create(String.class);
+ public static final AttachmentKey SERVER_PORT = AttachmentKey.create(Integer.class);
+ public static final AttachmentKey IS_SSL = AttachmentKey.create(Boolean.class);
+
+ public static final AttachmentKey REMOTE_USER = AttachmentKey.create(String.class);
+ public static final AttachmentKey AUTH_TYPE = AttachmentKey.create(String.class);
+ public static final AttachmentKey ROUTE = AttachmentKey.create(String.class);
+ public static final AttachmentKey SSL_CERT = AttachmentKey.create(String.class);
+ public static final AttachmentKey SSL_CYPHER = AttachmentKey.create(String.class);
+ public static final AttachmentKey SSL_SESSION_ID = AttachmentKey.create(byte[].class);
+ public static final AttachmentKey SSL_KEY_SIZE = AttachmentKey.create(Integer.class);
+ public static final AttachmentKey SECRET = AttachmentKey.create(String.class);
+
+}
Index: 3rdParty_sources/undertow/io/undertow/client/UndertowClient.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/UndertowClient.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/UndertowClient.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,177 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import org.xnio.FutureResult;
+import org.xnio.IoFuture;
+import org.xnio.OptionMap;
+import org.xnio.Pool;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.ssl.XnioSsl;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+/**
+ * Undertow client class. This class loads {@link ClientProvider} implementations, and uses them to
+ * create connections to a target.
+ *
+ * @author Stuart Douglas
+ */
+public final class UndertowClient {
+
+ private final Map clientProviders;
+
+ private static final UndertowClient INSTANCE = new UndertowClient();
+
+ private UndertowClient() {
+ this(UndertowClient.class.getClassLoader());
+ }
+
+ private UndertowClient(final ClassLoader classLoader) {
+ ServiceLoader providers = ServiceLoader.load(ClientProvider.class, classLoader);
+ final Map map = new HashMap<>();
+ for (ClientProvider provider : providers) {
+ for (String scheme : provider.handlesSchemes()) {
+ map.put(scheme, provider);
+ }
+ }
+ this.clientProviders = Collections.unmodifiableMap(map);
+ }
+
+ public IoFuture connect(final URI uri, final XnioWorker worker, Pool bufferPool, OptionMap options) {
+ return connect(uri, worker, null, bufferPool, options);
+ }
+
+ public IoFuture connect(InetSocketAddress bindAddress, final URI uri, final XnioWorker worker, Pool bufferPool, OptionMap options) {
+ return connect(bindAddress, uri, worker, null, bufferPool, options);
+ }
+
+ public IoFuture connect(final URI uri, final XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ return connect((InetSocketAddress) null, uri, worker, ssl, bufferPool, options);
+ }
+
+ public IoFuture connect(InetSocketAddress bindAddress, final URI uri, final XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ ClientProvider provider = getClientProvider(uri);
+ final FutureResult result = new FutureResult<>();
+ provider.connect(new ClientCallback() {
+ @Override
+ public void completed(ClientConnection r) {
+ result.setResult(r);
+ }
+
+ @Override
+ public void failed(IOException e) {
+ result.setException(e);
+ }
+ }, bindAddress, uri, worker, ssl, bufferPool, options);
+ return result.getIoFuture();
+ }
+
+ public IoFuture connect(final URI uri, final XnioIoThread ioThread, Pool bufferPool, OptionMap options) {
+ return connect((InetSocketAddress) null, uri, ioThread, null, bufferPool, options);
+ }
+
+
+ public IoFuture connect(InetSocketAddress bindAddress, final URI uri, final XnioIoThread ioThread, Pool bufferPool, OptionMap options) {
+ return connect(bindAddress, uri, ioThread, null, bufferPool, options);
+ }
+
+ public IoFuture connect(final URI uri, final XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ return connect((InetSocketAddress) null, uri, ioThread, ssl, bufferPool, options);
+ }
+
+ public IoFuture connect(InetSocketAddress bindAddress, final URI uri, final XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ ClientProvider provider = getClientProvider(uri);
+ final FutureResult result = new FutureResult<>();
+ provider.connect(new ClientCallback() {
+ @Override
+ public void completed(ClientConnection r) {
+ result.setResult(r);
+ }
+
+ @Override
+ public void failed(IOException e) {
+ result.setException(e);
+ }
+ }, bindAddress, uri, ioThread, ssl, bufferPool, options);
+ return result.getIoFuture();
+ }
+
+ public void connect(final ClientCallback listener, final URI uri, final XnioWorker worker, Pool bufferPool, OptionMap options) {
+ connect(listener, uri, worker, null, bufferPool, options);
+ }
+
+ public void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioWorker worker, Pool bufferPool, OptionMap options) {
+ connect(listener, bindAddress, uri, worker, null, bufferPool, options);
+ }
+
+ public void connect(final ClientCallback listener, final URI uri, final XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ ClientProvider provider = getClientProvider(uri);
+ provider.connect(listener, uri, worker, ssl, bufferPool, options);
+ }
+
+ public void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ ClientProvider provider = getClientProvider(uri);
+ provider.connect(listener, bindAddress, uri, worker, ssl, bufferPool, options);
+ }
+
+ public void connect(final ClientCallback listener, final URI uri, final XnioIoThread ioThread, Pool bufferPool, OptionMap options) {
+ connect(listener, uri, ioThread, null, bufferPool, options);
+ }
+
+
+ public void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioIoThread ioThread, Pool bufferPool, OptionMap options) {
+ connect(listener, bindAddress, uri, ioThread, null, bufferPool, options);
+ }
+
+ public void connect(final ClientCallback listener, final URI uri, final XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ ClientProvider provider = getClientProvider(uri);
+ provider.connect(listener, uri, ioThread, ssl, bufferPool, options);
+ }
+
+ public void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ ClientProvider provider = getClientProvider(uri);
+ provider.connect(listener, bindAddress, uri, ioThread, ssl, bufferPool, options);
+ }
+
+ private ClientProvider getClientProvider(URI uri) {
+ ClientProvider provider = clientProviders.get(uri.getScheme());
+ if (provider == null) {
+ throw UndertowClientMessages.MESSAGES.unknownScheme(uri);
+ }
+ return provider;
+ }
+
+ public static UndertowClient getInstance() {
+ return INSTANCE;
+ }
+
+ public static UndertowClient getInstance(final ClassLoader classLoader) {
+ return new UndertowClient(classLoader);
+ }
+
+}
Index: 3rdParty_sources/undertow/io/undertow/client/UndertowClientMessages.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/UndertowClientMessages.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/UndertowClientMessages.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client;
+
+import io.undertow.util.HttpString;
+import org.jboss.logging.Messages;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageBundle;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * starting from 1000
+ *
+ * @author Emanuel Muckenhuber
+ */
+@MessageBundle(projectCode = "UT")
+public interface UndertowClientMessages {
+
+ UndertowClientMessages MESSAGES = Messages.getBundle(UndertowClientMessages.class);
+
+ // 1000
+ @Message(id = 1000, value = "Connection closed")
+ String connectionClosed();
+
+ @Message(id = 1001, value = "Request already written")
+ IllegalStateException requestAlreadyWritten();
+
+ // 1020
+ @Message(id = 1020, value = "Failed to upgrade channel due to response %s (%s)")
+ String failedToUpgradeChannel(final int responseCode, String reason);
+
+ // 1030
+ @Message(id = 1030, value = "invalid content length %d")
+ IllegalArgumentException illegalContentLength(long length);
+
+ @Message(id = 1031, value = "Unknown scheme in URI %s")
+ IllegalArgumentException unknownScheme(URI uri);
+
+ @Message(id = 1032, value = "Unknown transfer encoding %s")
+ IOException unknownTransferEncoding(String transferEncodingString);
+
+ @Message(id = 1033, value = "Invalid connection state")
+ IOException invalidConnectionState();
+
+ @Message(id = 1034, value = "Unknown AJP packet type %s")
+ IOException unknownAjpMessageType(byte packetType);
+
+ @Message(id = 1035, value = "Unknown method type for AJP request %s")
+ IOException unknownMethod(HttpString method);
+
+ @Message(id = 1036, value = "Data still remaining in chunk %s")
+ IOException dataStillRemainingInChunk(long remaining);
+
+ @Message(id = 1037, value = "Wrong magic number, expected %s, actual %s")
+ IOException wrongMagicNumber(String expected, String actual);
+
+ @Message(id = 1038, value = "Received invalid AJP chunk %s with response already complete")
+ IOException receivedInvalidChunk(byte prefix);
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientConnection.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientConnection.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientConnection.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,321 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.ajp;
+
+import static io.undertow.util.Headers.CLOSE;
+import static io.undertow.util.Headers.CONNECTION;
+import static io.undertow.util.Headers.CONTENT_LENGTH;
+import static io.undertow.util.Headers.TRANSFER_ENCODING;
+import static io.undertow.util.Headers.UPGRADE;
+import static org.xnio.Bits.anyAreSet;
+import static org.xnio.IoUtils.safeClose;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import org.xnio.ChannelExceptionHandler;
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.OptionMap;
+import org.xnio.Pool;
+import org.xnio.StreamConnection;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.Channels;
+import org.xnio.channels.StreamSinkChannel;
+
+import io.undertow.UndertowLogger;
+import io.undertow.UndertowMessages;
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.client.UndertowClientMessages;
+import io.undertow.protocols.ajp.AbstractAjpClientStreamSourceChannel;
+import io.undertow.protocols.ajp.AjpClientChannel;
+import io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel;
+import io.undertow.protocols.ajp.AjpClientResponseStreamSourceChannel;
+import io.undertow.util.AbstractAttachable;
+import io.undertow.util.Protocols;
+
+/**
+ * @author David M. Lloyd
+ */
+class AjpClientConnection extends AbstractAttachable implements Closeable, ClientConnection {
+
+ public final ChannelListener requestFinishListener = new ChannelListener() {
+ @Override
+ public void handleEvent(AjpClientRequestClientStreamSinkChannel channel) {
+ currentRequest.terminateRequest();
+ }
+ };
+ public final ChannelListener responseFinishedListener = new ChannelListener() {
+ @Override
+ public void handleEvent(AjpClientResponseStreamSourceChannel channel) {
+ currentRequest.terminateResponse();
+ }
+ };
+
+ private final Deque pendingQueue = new ArrayDeque<>();
+ private AjpClientExchange currentRequest;
+
+ private final OptionMap options;
+ private final AjpClientChannel connection;
+
+ private final Pool bufferPool;
+
+ private static final int UPGRADED = 1 << 28;
+ private static final int UPGRADE_REQUESTED = 1 << 29;
+ private static final int CLOSE_REQ = 1 << 30;
+ private static final int CLOSED = 1 << 31;
+
+ private int state;
+
+ private final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter<>();
+ private final ClientReceiveListener clientReceiveListener = new ClientReceiveListener();
+
+ AjpClientConnection(final AjpClientChannel connection, final OptionMap options, final Pool bufferPool) {
+ this.options = options;
+ this.connection = connection;
+ this.bufferPool = bufferPool;
+
+ connection.addCloseTask(new ChannelListener() {
+ @Override
+ public void handleEvent(AjpClientChannel channel) {
+ ChannelListeners.invokeChannelListener(AjpClientConnection.this, closeSetter.get());
+ }
+ });
+ connection.getReceiveSetter().set(new ClientReceiveListener());
+ connection.resumeReceives();
+ }
+
+ @Override
+ public Pool getBufferPool() {
+ return bufferPool;
+ }
+
+
+ @Override
+ public SocketAddress getPeerAddress() {
+ return connection.getPeerAddress();
+ }
+
+ @Override
+ public A getPeerAddress(Class type) {
+ return connection.getPeerAddress(type);
+ }
+
+ @Override
+ public ChannelListener.Setter extends AjpClientConnection> getCloseSetter() {
+ return closeSetter;
+ }
+
+ @Override
+ public SocketAddress getLocalAddress() {
+ return connection.getLocalAddress();
+ }
+
+ @Override
+ public A getLocalAddress(Class type) {
+ return connection.getLocalAddress(type);
+ }
+
+ @Override
+ public XnioWorker getWorker() {
+ return connection.getWorker();
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return connection.getIoThread();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return connection.isOpen();
+ }
+
+ @Override
+ public boolean supportsOption(Option> option) {
+ return connection.supportsOption(option);
+ }
+
+
+ @Override
+ public T getOption(Option option) throws IOException {
+ return connection.getOption(option);
+ }
+
+ @Override
+ public T setOption(Option option, T value) throws IllegalArgumentException, IOException {
+ return connection.setOption(option, value);
+ }
+
+ @Override
+ public boolean isUpgraded() {
+ return anyAreSet(state, UPGRADE_REQUESTED | UPGRADED);
+ }
+
+ @Override
+ public void sendRequest(final ClientRequest request, final ClientCallback clientCallback) {
+ if (anyAreSet(state, UPGRADE_REQUESTED | UPGRADED | CLOSE_REQ | CLOSED)) {
+ clientCallback.failed(UndertowClientMessages.MESSAGES.invalidConnectionState());
+ return;
+ }
+ final AjpClientExchange AjpClientExchange = new AjpClientExchange(clientCallback, request, this);
+ if (currentRequest == null) {
+ initiateRequest(AjpClientExchange);
+ } else {
+ pendingQueue.add(AjpClientExchange);
+ }
+ }
+
+ private void initiateRequest(AjpClientExchange AjpClientExchange) {
+ currentRequest = AjpClientExchange;
+ ClientRequest request = AjpClientExchange.getRequest();
+
+ String connectionString = request.getRequestHeaders().getFirst(CONNECTION);
+ if (connectionString != null) {
+ if (CLOSE.equalToString(connectionString)) {
+ state |= CLOSE_REQ;
+ }
+ } else if (request.getProtocol() != Protocols.HTTP_1_1) {
+ state |= CLOSE_REQ;
+ }
+ if (request.getRequestHeaders().contains(UPGRADE)) {
+ state |= UPGRADE_REQUESTED;
+ }
+
+ long length = 0;
+ String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH);
+ String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING);
+
+ if (fixedLengthString != null) {
+ length = Long.parseLong(fixedLengthString);
+ } else if (transferEncodingString != null) {
+ length = -1;
+ }
+
+ AjpClientRequestClientStreamSinkChannel sinkChannel = connection.sendRequest(request.getMethod(), request.getPath(), request.getProtocol(), request.getRequestHeaders(), request, requestFinishListener);
+ currentRequest.setRequestChannel(sinkChannel);
+
+ AjpClientExchange.invokeReadReadyCallback(AjpClientExchange);
+ if (length == 0) {
+ //if there is no content we flush the response channel.
+ //otherwise it is up to the user
+ try {
+ sinkChannel.shutdownWrites();
+ if (!sinkChannel.flush()) {
+ handleFailedFlush(sinkChannel);
+ }
+ } catch (IOException e) {
+ handleError(e);
+ }
+ }
+ }
+
+ private void handleFailedFlush(AjpClientRequestClientStreamSinkChannel sinkChannel) {
+ sinkChannel.getWriteSetter().set(ChannelListeners.flushingChannelListener(null, new ChannelExceptionHandler() {
+ @Override
+ public void handleException(StreamSinkChannel channel, IOException exception) {
+ handleError(exception);
+ }
+ }));
+ sinkChannel.resumeWrites();
+ }
+
+ private void handleError(IOException exception) {
+ currentRequest.setFailed(exception);
+ safeClose(connection);
+ }
+
+ public StreamConnection performUpgrade() throws IOException {
+ throw UndertowMessages.MESSAGES.upgradeNotSupported();
+ }
+
+ public void close() throws IOException {
+ if (anyAreSet(state, CLOSED)) {
+ return;
+ }
+ state |= CLOSED | CLOSE_REQ;
+ connection.close();
+ }
+
+ /**
+ * Notification that the current request is finished
+ */
+ public void requestDone() {
+ currentRequest = null;
+
+ if (anyAreSet(state, CLOSE_REQ)) {
+ safeClose(connection);
+ } else if (anyAreSet(state, UPGRADE_REQUESTED)) {
+ safeClose(connection); //we don't support upgrade, just close the connection to be safe
+ return;
+ }
+
+ AjpClientExchange next = pendingQueue.poll();
+
+ if (next != null) {
+ initiateRequest(next);
+ }
+ }
+
+ public void requestClose() {
+ state |= CLOSE_REQ;
+ }
+
+
+ class ClientReceiveListener implements ChannelListener {
+
+ public void handleEvent(AjpClientChannel channel) {
+ try {
+ AbstractAjpClientStreamSourceChannel result = channel.receive();
+ if(result == null) {
+ return;
+ }
+
+ if(result instanceof AjpClientResponseStreamSourceChannel) {
+ AjpClientResponseStreamSourceChannel response = (AjpClientResponseStreamSourceChannel) result;
+ response.setFinishListener(responseFinishedListener);
+ ClientResponse cr = new ClientResponse(response.getStatusCode(), response.getReasonPhrase(), currentRequest.getRequest().getProtocol(), response.getHeaders());
+ if (response.getStatusCode() == 100) {
+ currentRequest.setContinueResponse(cr);
+ } else {
+ currentRequest.setResponseChannel(response);
+ currentRequest.setResponse(cr);
+ }
+ } else {
+ //TODO: ping, pong ETC
+ Channels.drain(result, Long.MAX_VALUE);
+ }
+
+ } catch (Exception e) {
+ UndertowLogger.CLIENT_LOGGER.exceptionProcessingRequest(e);
+ safeClose(connection);
+ currentRequest.setFailed(e instanceof IOException ? (IOException) e : new IOException(e));
+ }
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientExchange.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientExchange.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientExchange.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,197 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.ajp;
+
+import io.undertow.channels.DetachableStreamSinkChannel;
+import io.undertow.channels.DetachableStreamSourceChannel;
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.client.ContinueNotification;
+import io.undertow.protocols.ajp.AjpClientChannel;
+import io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel;
+import io.undertow.protocols.ajp.AjpClientResponseStreamSourceChannel;
+import io.undertow.util.AbstractAttachable;
+import io.undertow.util.Headers;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+import java.io.IOException;
+
+import static org.xnio.Bits.anyAreSet;
+
+/**
+ * @author Stuart Douglas
+ */
+class AjpClientExchange extends AbstractAttachable implements ClientExchange {
+
+ private final ClientRequest request;
+ private final boolean requiresContinue;
+ private final AjpClientConnection clientConnection;
+
+ private ClientCallback responseCallback;
+ private ClientCallback readyCallback;
+ private ContinueNotification continueNotification;
+ private AjpClientChannel ajpClientChannel;
+
+ private ClientResponse response;
+ private ClientResponse continueResponse;
+ private IOException failedReason;
+
+ private AjpClientResponseStreamSourceChannel responseChannel;
+ private AjpClientRequestClientStreamSinkChannel requestChannel;
+
+ private int state = 0;
+ private static final int REQUEST_TERMINATED = 1;
+ private static final int RESPONSE_TERMINATED = 1 << 1;
+
+ public AjpClientExchange(ClientCallback readyCallback, ClientRequest request, AjpClientConnection clientConnection) {
+ this.readyCallback = readyCallback;
+ this.request = request;
+ this.clientConnection = clientConnection;
+ boolean reqContinue = false;
+ if (request.getRequestHeaders().contains(Headers.EXPECT)) {
+ for (String header : request.getRequestHeaders().get(Headers.EXPECT)) {
+ if (header.equals("100-continue")) {
+ reqContinue = true;
+ }
+ }
+ }
+ this.requiresContinue = reqContinue;
+ }
+
+ void terminateRequest() {
+ state |= REQUEST_TERMINATED;
+ if (anyAreSet(state, RESPONSE_TERMINATED)) {
+ clientConnection.requestDone();
+ }
+ }
+
+ void terminateResponse() {
+ state |= RESPONSE_TERMINATED;
+ if (anyAreSet(state, REQUEST_TERMINATED)) {
+ clientConnection.requestDone();
+ }
+ }
+
+ public boolean isRequiresContinue() {
+ return requiresContinue;
+ }
+
+
+ void setContinueResponse(ClientResponse response) {
+ this.continueResponse = response;
+ if (continueNotification != null) {
+ this.continueNotification.handleContinue(this);
+ }
+ }
+
+ void setResponse(ClientResponse response) {
+ this.response = response;
+ if (responseCallback != null) {
+ this.responseCallback.completed(this);
+ }
+ }
+
+ @Override
+ public void setResponseListener(ClientCallback listener) {
+ this.responseCallback = listener;
+ if (listener != null) {
+ if (failedReason != null) {
+ listener.failed(failedReason);
+ } else if (response != null) {
+ listener.completed(this);
+ }
+ }
+ }
+
+ @Override
+ public void setContinueHandler(ContinueNotification continueHandler) {
+ this.continueNotification = continueHandler;
+ }
+
+ void setFailed(IOException e) {
+ this.failedReason = e;
+ if (readyCallback != null) {
+ readyCallback.failed(e);
+ readyCallback = null;
+ }
+ if (responseCallback != null) {
+ responseCallback.failed(e);
+ responseCallback = null;
+ }
+ }
+
+ @Override
+ public StreamSinkChannel getRequestChannel() {
+ return new DetachableStreamSinkChannel(requestChannel) {
+ @Override
+ protected boolean isFinished() {
+ return anyAreSet(state, REQUEST_TERMINATED);
+ }
+ };
+ }
+
+ @Override
+ public StreamSourceChannel getResponseChannel() {
+ return new DetachableStreamSourceChannel(responseChannel) {
+ @Override
+ protected boolean isFinished() {
+ return anyAreSet(state, RESPONSE_TERMINATED);
+ }
+ };
+ }
+
+ @Override
+ public ClientRequest getRequest() {
+ return request;
+ }
+
+ @Override
+ public ClientResponse getResponse() {
+ return response;
+ }
+
+ @Override
+ public ClientResponse getContinueResponse() {
+ return continueResponse;
+ }
+
+ @Override
+ public ClientConnection getConnection() {
+ return clientConnection;
+ }
+
+ void setResponseChannel(AjpClientResponseStreamSourceChannel responseChannel) {
+ this.responseChannel = responseChannel;
+ }
+
+ void setRequestChannel(AjpClientRequestClientStreamSinkChannel requestChannel) {
+ this.requestChannel = requestChannel;
+ }
+
+ void invokeReadReadyCallback(final ClientExchange result) {
+ if(readyCallback != null) {
+ readyCallback.completed(result);
+ readyCallback = null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientProvider.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientProvider.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/ajp/AjpClientProvider.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,113 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.ajp;
+
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientProvider;
+import io.undertow.protocols.ajp.AjpClientChannel;
+
+import org.xnio.ChannelListener;
+import org.xnio.IoFuture;
+import org.xnio.OptionMap;
+import org.xnio.Pool;
+import org.xnio.StreamConnection;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.ssl.XnioSsl;
+
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Stuart Douglas
+ */
+public class AjpClientProvider implements ClientProvider {
+
+ @Override
+ public Set handlesSchemes() {
+ return new HashSet<>(Arrays.asList(new String[]{"ajp"}));
+ }
+
+ @Override
+ public void connect(final ClientCallback listener, final URI uri, final XnioWorker worker, final XnioSsl ssl, final Pool bufferPool, final OptionMap options) {
+ connect(listener, null, uri, worker, ssl, bufferPool, options);
+ }
+
+ @Override
+ public void connect(final ClientCallback listener, final URI uri, final XnioIoThread ioThread, final XnioSsl ssl, final Pool bufferPool, final OptionMap options) {
+ connect(listener, null, uri, ioThread, ssl, bufferPool, options);
+ }
+
+ @Override
+ public void connect(final ClientCallback listener, InetSocketAddress bindAddress, final URI uri, final XnioWorker worker, final XnioSsl ssl, final Pool bufferPool, final OptionMap options) {
+ ChannelListener openListener = new ChannelListener() {
+ @Override
+ public void handleEvent(StreamConnection connection) {
+ handleConnected(connection, listener, uri, ssl, bufferPool, options);
+ }
+ };
+ IoFuture.Notifier notifier = new IoFuture.Notifier() {
+ @Override
+ public void notify(IoFuture extends StreamConnection> ioFuture, Object o) {
+ if (ioFuture.getStatus() == IoFuture.Status.FAILED) {
+ listener.failed(ioFuture.getException());
+ }
+ }
+ };
+ if(bindAddress == null) {
+ worker.openStreamConnection(new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 8009 : uri.getPort()), openListener, options).addNotifier(notifier, null);
+ } else {
+ worker.openStreamConnection(bindAddress, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 8009 : uri.getPort()), openListener, null, options).addNotifier(notifier, null);
+ }
+ }
+
+ @Override
+ public void connect(final ClientCallback listener, InetSocketAddress bindAddress,final URI uri, final XnioIoThread ioThread, final XnioSsl ssl, final Pool bufferPool, final OptionMap options) {
+ ChannelListener openListener = new ChannelListener() {
+ @Override
+ public void handleEvent(StreamConnection connection) {
+ handleConnected(connection, listener, uri, ssl, bufferPool, options);
+ }
+ };
+ IoFuture.Notifier notifier = new IoFuture.Notifier() {
+ @Override
+ public void notify(IoFuture extends StreamConnection> ioFuture, Object o) {
+ if (ioFuture.getStatus() == IoFuture.Status.FAILED) {
+ listener.failed(ioFuture.getException());
+ }
+ }
+ };
+ if(bindAddress == null) {
+ ioThread.openStreamConnection(new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 8009 : uri.getPort()), openListener, options).addNotifier(notifier, null);
+ } else {
+ ioThread.openStreamConnection(bindAddress, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 8009 : uri.getPort()), openListener, null, options).addNotifier(notifier, null);
+ }
+ }
+
+ private void handleConnected(StreamConnection connection, ClientCallback listener, URI uri, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ listener.completed(new AjpClientConnection(new AjpClientChannel(connection, bufferPool) , options, bufferPool));
+ }
+
+
+}
Index: 3rdParty_sources/undertow/io/undertow/client/http/ClientFixedLengthStreamSinkConduit.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/http/ClientFixedLengthStreamSinkConduit.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/http/ClientFixedLengthStreamSinkConduit.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.http;
+
+import io.undertow.conduits.AbstractFixedLengthStreamSinkConduit;
+import org.xnio.conduits.StreamSinkConduit;
+
+class ClientFixedLengthStreamSinkConduit extends AbstractFixedLengthStreamSinkConduit {
+
+ private final HttpClientExchange exchange;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param next the next channel
+ * @param contentLength the content length
+ * @param configurable {@code true} if this instance should pass configuration to the next
+ * @param propagateClose {@code true} if this instance should pass close to the next
+ * @param exchange
+ */
+ public ClientFixedLengthStreamSinkConduit(StreamSinkConduit next, long contentLength, boolean configurable, boolean propagateClose, HttpClientExchange exchange) {
+ super(next, contentLength, configurable, propagateClose);
+ this.exchange = exchange;
+ }
+
+
+
+ @Override
+ protected void channelFinished() {
+ exchange.terminateRequest();
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/http/HttpClientConnection.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/http/HttpClientConnection.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/http/HttpClientConnection.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,483 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.http;
+
+import io.undertow.UndertowLogger;
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.client.UndertowClientMessages;
+import io.undertow.conduits.ChunkedStreamSinkConduit;
+import io.undertow.conduits.ChunkedStreamSourceConduit;
+import io.undertow.conduits.ConduitListener;
+import io.undertow.conduits.FixedLengthStreamSourceConduit;
+import io.undertow.util.AbstractAttachable;
+import io.undertow.util.Headers;
+import io.undertow.util.HttpString;
+import io.undertow.util.Methods;
+import io.undertow.util.Protocols;
+import org.xnio.ChannelExceptionHandler;
+import org.xnio.ChannelListener;
+import org.xnio.ChannelListeners;
+import org.xnio.Option;
+import org.xnio.OptionMap;
+import org.xnio.Pool;
+import org.xnio.Pooled;
+import org.xnio.StreamConnection;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSourceChannel;
+import org.xnio.conduits.ConduitStreamSinkChannel;
+import org.xnio.conduits.ConduitStreamSourceChannel;
+import org.xnio.conduits.PushBackStreamSourceConduit;
+import org.xnio.conduits.StreamSinkConduit;
+import org.xnio.conduits.StreamSourceConduit;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Locale;
+
+import static io.undertow.client.UndertowClientMessages.MESSAGES;
+import static io.undertow.util.Headers.CLOSE;
+import static io.undertow.util.Headers.CONNECTION;
+import static io.undertow.util.Headers.CONTENT_LENGTH;
+import static io.undertow.util.Headers.TRANSFER_ENCODING;
+import static io.undertow.util.Headers.UPGRADE;
+import static org.xnio.Bits.allAreClear;
+import static org.xnio.Bits.allAreSet;
+import static org.xnio.Bits.anyAreSet;
+import static org.xnio.IoUtils.safeClose;
+
+/**
+ * @author David M. Lloyd
+ */
+class HttpClientConnection extends AbstractAttachable implements Closeable, ClientConnection {
+
+ public final ConduitListener requestFinishListener = new ConduitListener() {
+ @Override
+ public void handleEvent(StreamSinkConduit channel) {
+ currentRequest.terminateRequest();
+ }
+ };
+ public final ConduitListener responseFinishedListener = new ConduitListener() {
+ @Override
+ public void handleEvent(StreamSourceConduit channel) {
+ currentRequest.terminateResponse();
+ }
+ };
+
+ private final Deque pendingQueue = new ArrayDeque<>();
+ private HttpClientExchange currentRequest;
+ private HttpResponseBuilder pendingResponse;
+
+ private final OptionMap options;
+ private final StreamConnection connection;
+ private final PushBackStreamSourceConduit pushBackStreamSourceConduit;
+ private final ClientReadListener clientReadListener = new ClientReadListener();
+
+ private final Pool bufferPool;
+ private final StreamSinkConduit originalSinkConduit;
+
+ private static final int UPGRADED = 1 << 28;
+ private static final int UPGRADE_REQUESTED = 1 << 29;
+ private static final int CLOSE_REQ = 1 << 30;
+ private static final int CLOSED = 1 << 31;
+ private int count = 0;
+
+ private int state;
+
+ private final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter<>();
+
+ HttpClientConnection(final StreamConnection connection, final OptionMap options, final Pool bufferPool) {
+ this.options = options;
+ this.connection = connection;
+ this.pushBackStreamSourceConduit = new PushBackStreamSourceConduit(connection.getSourceChannel().getConduit());
+ this.connection.getSourceChannel().setConduit(pushBackStreamSourceConduit);
+ this.bufferPool = bufferPool;
+ this.originalSinkConduit = connection.getSinkChannel().getConduit();
+
+ connection.getCloseSetter().set(new ChannelListener() {
+
+ public void handleEvent(StreamConnection channel) {
+ HttpClientConnection.this.state |= CLOSED;
+ ChannelListeners.invokeChannelListener(HttpClientConnection.this, closeSetter.get());
+ }
+ });
+ }
+
+ @Override
+ public Pool getBufferPool() {
+ return bufferPool;
+ }
+
+
+ @Override
+ public SocketAddress getPeerAddress() {
+ return connection.getPeerAddress();
+ }
+
+ StreamConnection getConnection() {
+ return connection;
+ }
+
+ @Override
+ public A getPeerAddress(Class type) {
+ return connection.getPeerAddress(type);
+ }
+
+ @Override
+ public ChannelListener.Setter extends HttpClientConnection> getCloseSetter() {
+ return closeSetter;
+ }
+
+ @Override
+ public SocketAddress getLocalAddress() {
+ return connection.getLocalAddress();
+ }
+
+ @Override
+ public A getLocalAddress(Class type) {
+ return connection.getLocalAddress(type);
+ }
+
+ @Override
+ public XnioWorker getWorker() {
+ return connection.getWorker();
+ }
+
+ @Override
+ public XnioIoThread getIoThread() {
+ return connection.getIoThread();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return connection.isOpen() && allAreClear(state, CLOSE_REQ | CLOSED);
+ }
+
+ @Override
+ public boolean supportsOption(Option> option) {
+ return connection.supportsOption(option);
+ }
+
+
+ @Override
+ public T getOption(Option option) throws IOException {
+ return connection.getOption(option);
+ }
+
+ @Override
+ public T setOption(Option option, T value) throws IllegalArgumentException, IOException {
+ return connection.setOption(option, value);
+ }
+
+ @Override
+ public boolean isUpgraded() {
+ return anyAreSet(state, UPGRADE_REQUESTED | UPGRADED);
+ }
+
+ @Override
+ public void sendRequest(final ClientRequest request, final ClientCallback clientCallback) {
+ count++;
+ if (anyAreSet(state, UPGRADE_REQUESTED | UPGRADED | CLOSE_REQ | CLOSED)) {
+ clientCallback.failed(UndertowClientMessages.MESSAGES.invalidConnectionState());
+ return;
+ }
+ final HttpClientExchange httpClientExchange = new HttpClientExchange(clientCallback, request, this);
+ if (currentRequest == null) {
+ initiateRequest(httpClientExchange);
+ } else {
+ pendingQueue.add(httpClientExchange);
+ }
+ }
+
+ private void initiateRequest(HttpClientExchange httpClientExchange) {
+ currentRequest = httpClientExchange;
+ pendingResponse = new HttpResponseBuilder();
+ ClientRequest request = httpClientExchange.getRequest();
+
+ String connectionString = request.getRequestHeaders().getFirst(CONNECTION);
+ if (connectionString != null) {
+ HttpString connectionHttpString = new HttpString(connectionString);
+ if (connectionHttpString.equals(CLOSE)) {
+ state |= CLOSE_REQ;
+ } else if(connectionHttpString.equals(UPGRADE)) {
+ state |= UPGRADE_REQUESTED;
+ }
+ } else if (request.getProtocol() != Protocols.HTTP_1_1) {
+ state |= CLOSE_REQ;
+ }
+ if (request.getRequestHeaders().contains(UPGRADE)) {
+ state |= UPGRADE_REQUESTED;
+ }
+
+ //setup the client request conduits
+ final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
+ sourceChannel.setReadListener(clientReadListener);
+ sourceChannel.resumeReads();
+
+ ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel();
+ StreamSinkConduit conduit = originalSinkConduit;
+ conduit = new HttpRequestConduit(conduit, bufferPool, request);
+
+ String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH);
+ String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING);
+
+ boolean hasContent = true;
+
+ if (fixedLengthString != null) {
+ try {
+ long length = Long.parseLong(fixedLengthString);
+ conduit = new ClientFixedLengthStreamSinkConduit(conduit, length, false, false, currentRequest);
+ hasContent = length != 0;
+ } catch (NumberFormatException e) {
+ handleError(new IOException(e));
+ return;
+ }
+ } else if (transferEncodingString != null) {
+ if (!transferEncodingString.toLowerCase(Locale.ENGLISH).contains(Headers.CHUNKED.toString())) {
+ handleError(UndertowClientMessages.MESSAGES.unknownTransferEncoding(transferEncodingString));
+ return;
+ }
+ conduit = new ChunkedStreamSinkConduit(conduit, httpClientExchange.getConnection().getBufferPool(), false, false, httpClientExchange.getRequest().getRequestHeaders(), requestFinishListener, httpClientExchange);
+ } else {
+ conduit = new ClientFixedLengthStreamSinkConduit(conduit, 0, false, false, currentRequest);
+ hasContent = false;
+ }
+ sinkChannel.setConduit(conduit);
+
+ httpClientExchange.invokeReadReadyCallback(httpClientExchange);
+ if (!hasContent) {
+ //if there is no content we flush the response channel.
+ //otherwise it is up to the user
+ try {
+ sinkChannel.shutdownWrites();
+ if (!sinkChannel.flush()) {
+ sinkChannel.setWriteListener(ChannelListeners.flushingChannelListener(null, new ChannelExceptionHandler() {
+ @Override
+ public void handleException(ConduitStreamSinkChannel channel, IOException exception) {
+ handleError(exception);
+ }
+ }));
+ }
+ } catch (IOException e) {
+ handleError(e);
+ }
+ }
+ }
+
+ private void handleError(IOException exception) {
+ currentRequest.setFailed(exception);
+ UndertowLogger.REQUEST_IO_LOGGER.ioException(exception);
+ safeClose(connection);
+ }
+
+ public StreamConnection performUpgrade() throws IOException {
+
+ // Upgrade the connection
+ // Set the upgraded flag already to prevent new requests after this one
+ if (allAreSet(state, UPGRADED | CLOSE_REQ | CLOSED)) {
+ throw new IOException(UndertowClientMessages.MESSAGES.connectionClosed());
+ }
+ state |= UPGRADED;
+ return connection;
+ }
+
+ public void close() throws IOException {
+ if (anyAreSet(state, CLOSED)) {
+ return;
+ }
+ state |= CLOSED | CLOSE_REQ;
+ connection.close();
+ }
+
+ /**
+ * Notification that the current request is finished
+ */
+ public void requestDone() {
+
+ connection.getSinkChannel().setConduit(originalSinkConduit);
+ connection.getSourceChannel().setConduit(pushBackStreamSourceConduit);
+ connection.getSinkChannel().suspendWrites();
+ connection.getSinkChannel().setWriteListener(null);
+
+ if (anyAreSet(state, CLOSE_REQ)) {
+ currentRequest = null;
+ this.state |= CLOSED;
+ safeClose(connection);
+ } else if (anyAreSet(state, UPGRADE_REQUESTED)) {
+ connection.getSourceChannel().suspendReads();
+ currentRequest = null;
+ return;
+ }
+ currentRequest = null;
+
+ HttpClientExchange next = pendingQueue.poll();
+
+ if (next == null) {
+ //we resume reads, so if the target goes away we get notified
+ connection.getSourceChannel().setReadListener(clientReadListener);
+ connection.getSourceChannel().resumeReads();
+ } else {
+ initiateRequest(next);
+ }
+ }
+
+ class ClientReadListener implements ChannelListener {
+
+ public void handleEvent(StreamSourceChannel channel) {
+
+ HttpResponseBuilder builder = pendingResponse;
+ final Pooled pooled = bufferPool.allocate();
+ final ByteBuffer buffer = pooled.getResource();
+ boolean free = true;
+
+ try {
+
+ if (builder == null) {
+ //read ready when no request pending
+ buffer.clear();
+ try {
+ int res = channel.read(buffer);
+ if(res == -1) {
+ UndertowLogger.CLIENT_LOGGER.debugf("Connection to %s was closed by the target server", connection.getPeerAddress());
+ safeClose(HttpClientConnection.this);
+ } else if(res != 0) {
+ UndertowLogger.CLIENT_LOGGER.debugf("Target server %s sent unexpected data when no request pending, closing connection", connection.getPeerAddress());
+ safeClose(HttpClientConnection.this);
+ }
+ //otherwise it is a spurious notification
+ } catch (IOException e) {
+ if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) {
+ UndertowLogger.CLIENT_LOGGER.debugf(e, "Connection closed with IOException");
+ }
+ safeClose(connection);
+ }
+ return;
+ }
+ final ResponseParseState state = builder.getParseState();
+ int res;
+ do {
+ buffer.clear();
+ try {
+ res = channel.read(buffer);
+ } catch (IOException e) {
+ if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) {
+ UndertowLogger.CLIENT_LOGGER.debugf(e, "Connection closed with IOException");
+ }
+ safeClose(channel);
+ currentRequest.setFailed(new IOException(MESSAGES.connectionClosed()));
+ return;
+ }
+
+ if (res == 0) {
+ if (!channel.isReadResumed()) {
+ channel.getReadSetter().set(this);
+ channel.resumeReads();
+ }
+ return;
+ } else if (res == -1) {
+ channel.suspendReads();
+ safeClose(HttpClientConnection.this);
+ // Cancel the current active request
+ currentRequest.setFailed(new IOException(MESSAGES.connectionClosed()));
+ return;
+ }
+
+ buffer.flip();
+
+ HttpResponseParser.INSTANCE.handle(buffer, state, builder);
+ if (buffer.hasRemaining()) {
+ free = false;
+ pushBackStreamSourceConduit.pushBack(pooled);
+ }
+
+ } while (!state.isComplete());
+
+ final ClientResponse response = builder.build();
+
+ String connectionString = response.getResponseHeaders().getFirst(CONNECTION);
+
+ //check if an upgrade worked
+ if (anyAreSet(HttpClientConnection.this.state, UPGRADE_REQUESTED)) {
+ if ((connectionString == null || !UPGRADE.equalToString(connectionString)) && !response.getResponseHeaders().contains(UPGRADE)) {
+ //just unset the upgrade requested flag
+ HttpClientConnection.this.state &= ~UPGRADE_REQUESTED;
+ }
+ }
+
+ if(connectionString != null) {
+ if (HttpString.tryFromString(connectionString).equals(Headers.CLOSE)) {
+ HttpClientConnection.this.state |= CLOSE_REQ;
+ }
+ }
+
+ if (builder.getStatusCode() == 100) {
+ pendingResponse = new HttpResponseBuilder();
+ currentRequest.setContinueResponse(response);
+ } else {
+ prepareResponseChannel(response, currentRequest);
+ channel.getReadSetter().set(null);
+ channel.suspendReads();
+ pendingResponse = null;
+ currentRequest.setResponse(response);
+ }
+
+
+ } catch (Exception e) {
+ UndertowLogger.CLIENT_LOGGER.exceptionProcessingRequest(e);
+ safeClose(connection);
+ currentRequest.setFailed(new IOException(e));
+ } finally {
+ if (free) pooled.free();
+ }
+
+
+ }
+ }
+
+ private void prepareResponseChannel(ClientResponse response, ClientExchange exchange) {
+ String encoding = response.getResponseHeaders().getLast(TRANSFER_ENCODING);
+ boolean chunked = encoding != null && Headers.CHUNKED.equals(new HttpString(encoding));
+ String length = response.getResponseHeaders().getFirst(CONTENT_LENGTH);
+ if (exchange.getRequest().getMethod().equals(Methods.HEAD)) {
+ connection.getSourceChannel().setConduit(new FixedLengthStreamSourceConduit(connection.getSourceChannel().getConduit(), 0, responseFinishedListener));
+ } else if (chunked) {
+ connection.getSourceChannel().setConduit(new ChunkedStreamSourceConduit(connection.getSourceChannel().getConduit(), pushBackStreamSourceConduit, bufferPool, responseFinishedListener, exchange));
+ } else if (length != null) {
+ try {
+ long contentLength = Long.parseLong(length);
+ connection.getSourceChannel().setConduit(new FixedLengthStreamSourceConduit(connection.getSourceChannel().getConduit(), contentLength, responseFinishedListener));
+ } catch (NumberFormatException e) {
+ handleError(new IOException(e));
+ throw e;
+ }
+ } else if (response.getProtocol().equals(Protocols.HTTP_1_1)) {
+ connection.getSourceChannel().setConduit(new FixedLengthStreamSourceConduit(connection.getSourceChannel().getConduit(), 0, responseFinishedListener));
+ } else {
+ state |= CLOSE_REQ;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/http/HttpClientExchange.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/http/HttpClientExchange.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/http/HttpClientExchange.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,182 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.http;
+
+import io.undertow.channels.DetachableStreamSinkChannel;
+import io.undertow.channels.DetachableStreamSourceChannel;
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.client.ContinueNotification;
+import io.undertow.util.AbstractAttachable;
+import io.undertow.util.Headers;
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.channels.StreamSourceChannel;
+
+import java.io.IOException;
+
+import static org.xnio.Bits.anyAreSet;
+
+/**
+ * @author Stuart Douglas
+ */
+class HttpClientExchange extends AbstractAttachable implements ClientExchange {
+
+ private final ClientRequest request;
+ private final boolean requiresContinue;
+ private final HttpClientConnection clientConnection;
+
+ private ClientCallback responseCallback;
+ private ClientCallback readyCallback;
+ private ContinueNotification continueNotification;
+
+ private ClientResponse response;
+ private ClientResponse continueResponse;
+ private IOException failedReason;
+
+ private int state = 0;
+ private static final int REQUEST_TERMINATED = 1;
+ private static final int RESPONSE_TERMINATED = 1 << 1;
+
+ public HttpClientExchange(ClientCallback readyCallback, ClientRequest request, HttpClientConnection clientConnection) {
+ this.readyCallback = readyCallback;
+ this.request = request;
+ this.clientConnection = clientConnection;
+ boolean reqContinue = false;
+ if (request.getRequestHeaders().contains(Headers.EXPECT)) {
+ for (String header : request.getRequestHeaders().get(Headers.EXPECT)) {
+ if (header.equals("100-continue")) {
+ reqContinue = true;
+ }
+ }
+ }
+ this.requiresContinue = reqContinue;
+ }
+
+ void terminateRequest() {
+ state |= REQUEST_TERMINATED;
+ if (anyAreSet(state, RESPONSE_TERMINATED)) {
+ clientConnection.requestDone();
+ }
+ }
+
+ void terminateResponse() {
+ state |= RESPONSE_TERMINATED;
+ if (anyAreSet(state, REQUEST_TERMINATED)) {
+ clientConnection.requestDone();
+ }
+ }
+
+ public boolean isRequiresContinue() {
+ return requiresContinue;
+ }
+
+
+ void setContinueResponse(ClientResponse response) {
+ this.continueResponse = response;
+ if (continueNotification != null) {
+ this.continueNotification.handleContinue(this);
+ }
+ }
+
+ void setResponse(ClientResponse response) {
+ this.response = response;
+ if (responseCallback != null) {
+ this.responseCallback.completed(this);
+ }
+ }
+
+ @Override
+ public void setResponseListener(ClientCallback listener) {
+ this.responseCallback = listener;
+ if (listener != null) {
+ if (failedReason != null) {
+ listener.failed(failedReason);
+ } else if (response != null) {
+ listener.completed(this);
+ }
+ }
+ }
+
+ @Override
+ public void setContinueHandler(ContinueNotification continueHandler) {
+ this.continueNotification = continueHandler;
+ }
+
+ void setFailed(IOException e) {
+ this.failedReason = e;
+ if (readyCallback != null) {
+ readyCallback.failed(e);
+ readyCallback = null;
+ }
+ if (responseCallback != null) {
+ responseCallback.failed(e);
+ responseCallback = null;
+ }
+ }
+
+ @Override
+ public StreamSinkChannel getRequestChannel() {
+ return new DetachableStreamSinkChannel(clientConnection.getConnection().getSinkChannel()) {
+ @Override
+ protected boolean isFinished() {
+ return anyAreSet(state, REQUEST_TERMINATED);
+ }
+ };
+ }
+
+ @Override
+ public StreamSourceChannel getResponseChannel() {
+ return new DetachableStreamSourceChannel(clientConnection.getConnection().getSourceChannel()) {
+ @Override
+ protected boolean isFinished() {
+ return anyAreSet(state, RESPONSE_TERMINATED);
+ }
+ };
+ }
+
+ @Override
+ public ClientRequest getRequest() {
+ return request;
+ }
+
+ @Override
+ public ClientResponse getResponse() {
+ return response;
+ }
+
+ @Override
+ public ClientResponse getContinueResponse() {
+ return continueResponse;
+ }
+
+ @Override
+ public ClientConnection getConnection() {
+ return clientConnection;
+ }
+
+ void invokeReadReadyCallback(final ClientExchange result) {
+ if(readyCallback != null) {
+ readyCallback.completed(result);
+ readyCallback = null;
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/http/HttpClientProvider.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/http/HttpClientProvider.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/http/HttpClientProvider.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,156 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.http;
+
+import io.undertow.UndertowMessages;
+import io.undertow.UndertowOptions;
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientProvider;
+import io.undertow.client.http2.Http2ClientProvider;
+import io.undertow.client.spdy.SpdyClientProvider;
+import org.xnio.ChannelListener;
+import org.xnio.IoFuture;
+import org.xnio.OptionMap;
+import org.xnio.Pool;
+import org.xnio.StreamConnection;
+import org.xnio.XnioIoThread;
+import org.xnio.XnioWorker;
+import org.xnio.ssl.SslConnection;
+import org.xnio.ssl.XnioSsl;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Stuart Douglas
+ */
+public class HttpClientProvider implements ClientProvider {
+
+ @Override
+ public Set handlesSchemes() {
+ return new HashSet<>(Arrays.asList(new String[]{"http", "https"}));
+ }
+
+ @Override
+ public void connect(final ClientCallback listener, final URI uri, final XnioWorker worker, final XnioSsl ssl, final Pool bufferPool, final OptionMap options) {
+ connect(listener, null, uri, worker, ssl, bufferPool, options);
+ }
+
+ @Override
+ public void connect(final ClientCallback listener, final URI uri, final XnioIoThread ioThread, final XnioSsl ssl, final Pool bufferPool, final OptionMap options) {
+ connect(listener, null, uri, ioThread, ssl, bufferPool, options);
+ }
+
+ @Override
+ public void connect(ClientCallback listener, InetSocketAddress bindAddress, URI uri, XnioWorker worker, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ if (uri.getScheme().equals("https")) {
+ if (ssl == null) {
+ listener.failed(UndertowMessages.MESSAGES.sslWasNull());
+ return;
+ }
+ if (bindAddress == null) {
+ ssl.openSslConnection(worker, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 443 : uri.getPort()), createOpenListener(listener, bufferPool, options), options).addNotifier(createNotifier(listener), null);
+ } else {
+ ssl.openSslConnection(worker, bindAddress, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 443 : uri.getPort()), createOpenListener(listener, bufferPool, options), options).addNotifier(createNotifier(listener), null);
+ }
+ } else {
+ if (bindAddress == null) {
+ worker.openStreamConnection(new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort()), createOpenListener(listener, bufferPool, options), options).addNotifier(createNotifier(listener), null);
+ } else {
+ worker.openStreamConnection(bindAddress, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort()), createOpenListener(listener, bufferPool, options), null, options).addNotifier(createNotifier(listener), null);
+ }
+ }
+ }
+
+ @Override
+ public void connect(ClientCallback listener, InetSocketAddress bindAddress, URI uri, XnioIoThread ioThread, XnioSsl ssl, Pool bufferPool, OptionMap options) {
+ if (uri.getScheme().equals("https")) {
+ if (ssl == null) {
+ listener.failed(UndertowMessages.MESSAGES.sslWasNull());
+ return;
+ }
+ if (bindAddress == null) {
+ ssl.openSslConnection(ioThread, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 443 : uri.getPort()), createOpenListener(listener, bufferPool, options), options).addNotifier(createNotifier(listener), null);
+ } else {
+ ssl.openSslConnection(ioThread, bindAddress, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 443 : uri.getPort()), createOpenListener(listener, bufferPool, options), options).addNotifier(createNotifier(listener), null);
+ }
+ } else {
+ if (bindAddress == null) {
+ ioThread.openStreamConnection(new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort()), createOpenListener(listener, bufferPool, options), options).addNotifier(createNotifier(listener), null);
+ } else {
+ ioThread.openStreamConnection(bindAddress, new InetSocketAddress(uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort()), createOpenListener(listener, bufferPool, options), null, options).addNotifier(createNotifier(listener), null);
+ }
+ }
+ }
+
+ private IoFuture.Notifier createNotifier(final ClientCallback listener) {
+ return new IoFuture.Notifier() {
+ @Override
+ public void notify(IoFuture extends StreamConnection> ioFuture, Object o) {
+ if (ioFuture.getStatus() == IoFuture.Status.FAILED) {
+ listener.failed(ioFuture.getException());
+ }
+ }
+ };
+ }
+
+ private ChannelListener createOpenListener(final ClientCallback listener, final Pool bufferPool, final OptionMap options) {
+ return new ChannelListener() {
+ @Override
+ public void handleEvent(StreamConnection connection) {
+ handleConnected(connection, listener, bufferPool, options);
+ }
+ };
+ }
+
+
+ private void handleConnected(final StreamConnection connection, final ClientCallback listener, final Pool bufferPool, final OptionMap options) {
+ if (options.get(UndertowOptions.ENABLE_SPDY, false) && connection instanceof SslConnection && SpdyClientProvider.isEnabled()) {
+ try {
+ SpdyClientProvider.handlePotentialSpdyConnection(connection, listener, bufferPool, options, new ChannelListener() {
+ @Override
+ public void handleEvent(SslConnection channel) {
+ listener.completed(new HttpClientConnection(connection, options, bufferPool));
+ }
+ });
+ } catch (Exception e) {
+ listener.failed(new IOException(e));
+ }
+ } else if (options.get(UndertowOptions.ENABLE_HTTP2, false) && connection instanceof SslConnection && Http2ClientProvider.isEnabled()) {
+ try {
+ Http2ClientProvider.handlePotentialHttp2Connection(connection, listener, bufferPool, options, new ChannelListener() {
+ @Override
+ public void handleEvent(SslConnection channel) {
+ listener.completed(new HttpClientConnection(connection, options, bufferPool));
+ }
+ });
+ } catch (Exception e) {
+ listener.failed(new IOException(e));
+ }
+ } else {
+ listener.completed(new HttpClientConnection(connection, options, bufferPool));
+ }
+ }
+}
Index: 3rdParty_sources/undertow/io/undertow/client/http/HttpRequestConduit.java
===================================================================
diff -u
--- 3rdParty_sources/undertow/io/undertow/client/http/HttpRequestConduit.java (revision 0)
+++ 3rdParty_sources/undertow/io/undertow/client/http/HttpRequestConduit.java (revision a0b759c0e2c1f081e1d2d10e5e8e6565b4e74505)
@@ -0,0 +1,622 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * 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 io.undertow.client.http;
+
+import io.undertow.client.ClientRequest;
+import io.undertow.server.TruncatedResponseException;
+import io.undertow.util.HeaderMap;
+import io.undertow.util.HttpString;
+import org.jboss.logging.Logger;
+import org.xnio.Pool;
+import org.xnio.Pooled;
+import org.xnio.XnioWorker;
+import org.xnio.channels.StreamSourceChannel;
+import org.xnio.conduits.AbstractStreamSinkConduit;
+import org.xnio.conduits.Conduits;
+import org.xnio.conduits.StreamSinkConduit;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
+import java.util.Iterator;
+
+import static org.xnio.Bits.allAreClear;
+import static org.xnio.Bits.allAreSet;
+
+/**
+ * @author David M. Lloyd
+ * @author Emanuel Muckenhuber
+ */
+final class HttpRequestConduit extends AbstractStreamSinkConduit {
+
+ private static final Logger log = Logger.getLogger("io.undertow.client.request");
+
+ private final Pool pool;
+
+ private int state = STATE_START;
+
+ private Iterator nameIterator;
+ private String string;
+ private HttpString headerName;
+ private Iterator valueIterator;
+ private int charIndex;
+ private Pooled