All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.gateway.handlers.detecting.DetectingGatewayProtocolHandler Maven / Gradle / Ivy

There is a newer version: 2.2.22
Show newest version
/**
 * Copyright (C) FuseSource, Inc.
 * http://fusesource.com
 *
 * 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.fabric8.gateway.handlers.detecting;

import io.fabric8.common.util.Strings;
import io.fabric8.gateway.ServiceDetails;
import io.fabric8.gateway.SocketWrapper;
import io.fabric8.gateway.handlers.detecting.protocol.ssl.SslSocketWrapper;
import io.fabric8.gateway.loadbalancer.ClientRequestFacadeFactory;
import io.fabric8.gateway.loadbalancer.ConnectionParameters;
import io.fabric8.gateway.loadbalancer.LoadBalancer;
import io.fabric8.gateway.ServiceMap;
import io.fabric8.gateway.handlers.detecting.protocol.ssl.SslConfig;
import io.fabric8.gateway.loadbalancer.ClientRequestFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vertx.java.core.AsyncResult;
import org.vertx.java.core.Handler;
import org.vertx.java.core.Vertx;
import org.vertx.java.core.buffer.Buffer;
import org.vertx.java.core.net.NetClient;
import org.vertx.java.core.net.NetSocket;
import org.vertx.java.core.streams.Pump;
import org.vertx.java.core.streams.ReadStream;

import javax.net.ssl.SSLContext;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * The initial vertx socket handler of a DetectingGateway.
 */
public class DetectingGatewayProtocolHandler implements Handler {
    private static final transient Logger LOG = LoggerFactory.getLogger(DetectingGatewayProtocolHandler.class);

    Vertx vertx;
    ServiceMap serviceMap;
    LoadBalancer serviceLoadBalancer;
    String defaultVirtualHost;
    ArrayList protocols;
    int maxProtocolIdentificationLength;
    ClientRequestFacadeFactory clientRequestFacadeFactory = new ClientRequestFacadeFactory("PROTOCOL_SESSION_ID, PROTOCOL_CLIENT_ID, REMOTE_ADDRESS");
    final AtomicReference httpGateway = new AtomicReference();
    SslConfig sslConfig;

    public Vertx getVertx() {
        return vertx;
    }

    public void setVertx(Vertx vertx) {
        this.vertx = vertx;
    }

    public void setServiceMap(ServiceMap serviceMap) {
        this.serviceMap = serviceMap;
    }

    public LoadBalancer getServiceLoadBalancer() {
        return serviceLoadBalancer;
    }

    public void setServiceLoadBalancer(LoadBalancer serviceLoadBalancer) {
        this.serviceLoadBalancer = serviceLoadBalancer;
    }

    public String getDefaultVirtualHost() {
        return defaultVirtualHost;
    }

    public void setDefaultVirtualHost(String defaultVirtualHost) {
        this.defaultVirtualHost = defaultVirtualHost;
    }

    public ArrayList getProtocols() {
        return protocols;
    }

    public void setProtocols(ArrayList protocols) {
        this.protocols = new ArrayList(protocols);
        int max = 0;
        for (Protocol protocol : protocols) {
            if( protocol.getMaxIdentificationLength() > max ) {
                max = protocol.getMaxIdentificationLength();
            }
        }
        maxProtocolIdentificationLength = max;
    }

    public Collection getProtocolNames() {
        ArrayList rc = new ArrayList(protocols.size());
        for (Protocol protocol : protocols) {
            rc.add(protocol.getProtocolName());
        }
        return rc;
    }

    SSLContext sslContext;
    SslSocketWrapper.ClientAuth clientAuth = SslSocketWrapper.ClientAuth.WANT;

    @Override
    public void handle(final SocketWrapper socket) {
        ReadStream readStream = socket.readStream();
        readStream.exceptionHandler(new Handler() {
            @Override
            public void handle(Throwable e) {
                LOG.info(String.format("Failed to route gateway client '%s' due to: %s", socket.remoteAddress(), e), e);
                socket.close();
            }
        });
        readStream.endHandler(new Handler() {
            @Override
            public void handle(Void event) {
                LOG.info(String.format("Gateway client '%s' closed the connection before it could be routed.", socket.remoteAddress()));
                socket.close();
            }
        });
        readStream.dataHandler(new Handler() {
            Buffer received = new Buffer();

            @Override
            public void handle(Buffer event) {
                received.appendBuffer(event);
                for (final Protocol protocol : protocols) {
                    if (protocol.matches(received)) {
                        if ("ssl".equals(protocol.getProtocolName())) {

                            LOG.info(String.format("SSL Connection from '%s'", socket.remoteAddress()));
                            String disabledCypherSuites=null;
                            String enabledCipherSuites=null;
                            if (sslConfig != null) {
                                disabledCypherSuites = sslConfig.getDisabledCypherSuites();
                                enabledCipherSuites = sslConfig.getEnabledCipherSuites();
                            }
                            if (sslContext == null) {
                                try {
                                    if (sslConfig != null) {
                                        sslContext = SSLContext.getInstance(sslConfig.getProtocol());
                                        sslContext.init(sslConfig.getKeyManagers(), sslConfig.getTrustManagers(), null);
                                    } else {
                                        sslContext = SSLContext.getDefault();
                                    }
                                } catch (Exception e) {
                                    LOG.warn("Could initialize SSL: " + e, e);
                                    socket.close();
                                    return;
                                }
                            }

                            // lets wrap it up in a SslSocketWrapper.
                            SslSocketWrapper sslSocketWrapper = new SslSocketWrapper(socket);
                            sslSocketWrapper.putBackHeader(received);
                            sslSocketWrapper.initServer(sslContext, clientAuth, disabledCypherSuites, enabledCipherSuites);
                            DetectingGatewayProtocolHandler.this.handle(sslSocketWrapper);
                            return;

                        } else if ("http".equals(protocol.getProtocolName())) {
                            InetSocketAddress target = getHttpGateway();
                            if (target != null) {
                                try {
                                    URI url = new URI("http://" + target.getHostString() + ":" + target.getPort());
                                    LOG.info(String.format("Connecting '%s' to '%s:%d' using the http protocol",
                                            socket.remoteAddress(), url.getHost(), url.getPort()));
                                    createClient(socket, url, received);
                                    return;
                                } catch (URISyntaxException e) {
                                    LOG.warn("Could not build valid connect URI.", e);
                                    socket.close();
                                    return;
                                }
                            } else {
                                LOG.info("No http gateway available for the http protocol");
                                socket.close();
                                return;
                            }
                        } else {
                            protocol.snoopConnectionParameters(socket, received, new Handler() {
                                @Override
                                public void handle(ConnectionParameters connectionParameters) {
                                    // this will install a new dataHandler on the socket.
                                    if (connectionParameters.protocol == null)
                                        connectionParameters.protocol = protocol.getProtocolName();
                                    if (connectionParameters.protocolSchemes == null)
                                        connectionParameters.protocolSchemes = protocol.getProtocolSchemes();
                                    route(socket, connectionParameters, received);
                                }
                            });
                            return;
                        }
                    }
                }
                if (received.length() >= maxProtocolIdentificationLength) {
                    LOG.info("Connection did not use one of the enabled protocols " + getProtocolNames());
                    socket.close();
                }
            }
        });
    }

    public void route(final SocketWrapper socket, ConnectionParameters params, final Buffer received) {
        NetClient client = null;

        if( params.protocolVirtualHost==null ) {
            params.protocolVirtualHost = defaultVirtualHost;
        }
        HashSet schemes = new HashSet(Arrays.asList(params.protocolSchemes));
        if(params.protocolVirtualHost!=null) {
            List services = serviceMap.getServices(params.protocolVirtualHost);

            // Lets try again with the defaultVirtualHost
            if( services.isEmpty() && !params.protocolVirtualHost.equals(defaultVirtualHost) ) {
                params.protocolVirtualHost = defaultVirtualHost;
                services = serviceMap.getServices(params.protocolVirtualHost);
            }

            LOG.debug(String.format("%d services match the virtual host", services.size()));
            if (!services.isEmpty()) {
                ClientRequestFacade clientRequestFacade = clientRequestFacadeFactory.create(socket, params);
                ServiceDetails serviceDetails = serviceLoadBalancer.choose(services, clientRequestFacade);
                if (serviceDetails != null) {
                    List urlStrings = serviceDetails.getServices();
                    LOG.debug("Selected service exposes the following URLS: {}", urlStrings);
                    for (String urlString : urlStrings) {
                        if (Strings.notEmpty(urlString)) {
                            // lets create a client for this request...
                            try {
                                URI uri = new URI(urlString);
                                //URL url = new URL(urlString);
                                String urlProtocol = uri.getScheme();
                                if (schemes.contains(urlProtocol)) {
                                    LOG.info(String.format("Connecting '%s' requesting virtual host '%s' with client key '%s' to '%s:%d' using the %s protocol",
                                        socket.remoteAddress(), params.protocolVirtualHost, clientRequestFacade.getClientRequestKey(), uri.getHost(), uri.getPort(), params.protocol
                                      ));

                                    client = createClient(socket, uri, received);
                                    break;
                                }
                            } catch (URISyntaxException e) {
                                LOG.warn("Failed to parse URI: " + urlString + ". " + e, e);
                            }
                        }
                    }
                }
            }
        }

        if (client == null) {
            // failed to route
            LOG.info(String.format("No endpoint available for virtual host '%s' and protocol %s", params.protocolVirtualHost, params.protocol));
            socket.close();
        }
    }

    /**
     * Creates a new client for the given URL and handler
     */
    private NetClient createClient(final SocketWrapper socketFromClient, URI url, final Buffer received) {
        return vertx.createNetClient().connect(url.getPort(), url.getHost(), new Handler>() {
            public void handle(final AsyncResult asyncSocket) {
                final NetSocket socketToServer = asyncSocket.result();

                Handler endHandler = new Handler() {
                    @Override
                    public void handle(Void event) {
                        socketFromClient.close();
                        socketToServer.close();
                    }
                };
                Handler exceptionHandler = new Handler() {
                    @Override
                    public void handle(Throwable event) {
                        socketFromClient.close();
                        socketToServer.close();
                    }
                };
                socketFromClient.readStream().endHandler(endHandler);
                socketFromClient.readStream().exceptionHandler(exceptionHandler);
                socketToServer.endHandler(endHandler);
                socketToServer.exceptionHandler(exceptionHandler);

                socketToServer.write(received);
                Pump.createPump(socketToServer, socketFromClient.writeStream()).start();
                Pump.createPump(socketFromClient.readStream(), socketToServer).start();
            }
        });
    }

    public ServiceMap getServiceMap() {
        return serviceMap;
    }

    public InetSocketAddress getHttpGateway() {
        return httpGateway.get();
    }
    public void setHttpGateway(InetSocketAddress value) {
        httpGateway.set(value);
    }

    public SslConfig getSslConfig() {
        return sslConfig;
    }

    public void setSslConfig(SslConfig sslConfig) {
        this.sslConfig = sslConfig;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy