KNOX-2779 - support multiple hosts for gateway.host config (#613)

diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 5f80fe5..6d61880 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -399,50 +399,53 @@
    *                     use the port provided in GatewayConfig.
    * @param topologyName Connector name, only used when not null
    */
-  private Connector createConnector(final Server server,
+  private List<Connector> createConnector(final Server server,
       final GatewayConfig config, final int port, final String topologyName)
       throws IOException, CertificateException, NoSuchAlgorithmException,
       KeyStoreException, AliasServiceException {
 
-    ServerConnector connector;
+    List<Connector> connectors = new ArrayList<>();
 
     // Determine the socket address and check availability.
-    InetSocketAddress address = config.getGatewayAddress();
-    checkAddressAvailability( address );
+    List<InetSocketAddress> addressList = config.getGatewayAddress();
+    for (InetSocketAddress address : addressList) {
+      ServerConnector connector;
+      checkAddressAvailability( address );
 
-    final int connectorPort = port > 0 ? port : address.getPort();
+      final int connectorPort = port > 0 ? port : address.getPort();
 
-    checkPortConflict(connectorPort, topologyName, config);
+      checkPortConflict(connectorPort, topologyName, config);
 
-    HttpConfiguration httpConfig = new HttpConfiguration();
-    httpConfig.setRequestHeaderSize( config.getHttpServerRequestHeaderBuffer() );
-    httpConfig.setResponseHeaderSize( config.getHttpServerResponseHeaderBuffer() );
-    httpConfig.setOutputBufferSize( config.getHttpServerResponseBuffer() );
+      HttpConfiguration httpConfig = new HttpConfiguration();
+      httpConfig.setRequestHeaderSize( config.getHttpServerRequestHeaderBuffer() );
+      httpConfig.setResponseHeaderSize( config.getHttpServerResponseHeaderBuffer() );
+      httpConfig.setOutputBufferSize( config.getHttpServerResponseBuffer() );
 
-    if (config.isSSLEnabled()) {
-      HttpConfiguration httpsConfig = new HttpConfiguration( httpConfig );
-      httpsConfig.setSecureScheme( "https" );
-      httpsConfig.setSecurePort( connectorPort );
-      httpsConfig.addCustomizer( new SecureRequestCustomizer() );
-      SSLService ssl = services.getService(ServiceType.SSL_SERVICE);
-      SslContextFactory sslContextFactory = (SslContextFactory)ssl.buildSslContextFactory( config );
-      connector = new ServerConnector( server, sslContextFactory, new HttpConnectionFactory( httpsConfig ) );
-    } else {
-      connector = new ServerConnector( server );
+      if (config.isSSLEnabled()) {
+        HttpConfiguration httpsConfig = new HttpConfiguration( httpConfig );
+        httpsConfig.setSecureScheme( "https" );
+        httpsConfig.setSecurePort( connectorPort );
+        httpsConfig.addCustomizer( new SecureRequestCustomizer() );
+        SSLService ssl = services.getService(ServiceType.SSL_SERVICE);
+        SslContextFactory sslContextFactory = (SslContextFactory)ssl.buildSslContextFactory( config );
+        connector = new ServerConnector( server, sslContextFactory, new HttpConnectionFactory( httpsConfig ) );
+      } else {
+        connector = new ServerConnector( server );
+      }
+      connector.setHost( address.getHostName() );
+      connector.setPort( connectorPort );
+
+      if(!StringUtils.isBlank(topologyName)) {
+        connector.setName(topologyName);
+      }
+
+      long idleTimeout = config.getGatewayIdleTimeout();
+      if (idleTimeout > 0L) {
+        connector.setIdleTimeout(idleTimeout);
+      }
+      connectors.add(connector);
     }
-    connector.setHost( address.getHostName() );
-    connector.setPort( connectorPort );
-
-    if(!StringUtils.isBlank(topologyName)) {
-      connector.setName(topologyName);
-    }
-
-    long idleTimeout = config.getGatewayIdleTimeout();
-    if (idleTimeout > 0L) {
-      connector.setIdleTimeout(idleTimeout);
-    }
-
-    return connector;
+    return connectors;
   }
 
   private static HandlerCollection createHandlers(
@@ -605,7 +608,10 @@
     log.setMaxFormKeys(config.getJettyMaxFormKeys());
 
     /* topologyName is null because all topology listen on this port */
-    jetty.addConnector( createConnector( jetty, config, config.getGatewayPort(), null) );
+    List<Connector> connectors = createConnector( jetty, config, config.getGatewayPort(), null);
+    for (Connector connector : connectors) {
+      jetty.addConnector(connector);
+    }
 
 
     // Add Annotations processing into the Jetty server to support JSPs
@@ -659,8 +665,10 @@
         if(deployedTopologyList.contains(entry.getKey()) && (entry.getValue() != config.getGatewayPort()) ) {
           log.createJettyConnector(entry.getKey().toLowerCase(Locale.ROOT), entry.getValue());
           try {
-            jetty.addConnector(createConnector(jetty, config, entry.getValue(),
-                entry.getKey().toLowerCase(Locale.ROOT)));
+            connectors = createConnector(jetty, config, entry.getValue(), entry.getKey().toLowerCase(Locale.ROOT));
+            for (Connector connector : connectors) {
+              jetty.addConnector(connector);
+            }
           } catch(final IOException e) {
             /* in case of port conflict we log error and move on */
             if( e.toString().contains("ports for topologies (if defined) have to be unique.") ) {
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index ba572a2..f2e8cd4 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -476,8 +476,14 @@
   }
 
   @Override
-  public String getGatewayHost() {
-    return get( HTTP_HOST, "0.0.0.0" );
+  public List<String> getGatewayHost() {
+    String hosts = get( HTTP_HOST, "0.0.0.0" );
+    String[] hostArray = hosts.split(",");
+    List<String> hostIps = new ArrayList<>();
+    for (String host : hostArray) {
+      hostIps.add(host.trim());
+    }
+    return hostIps;
   }
 
   @Override
@@ -521,10 +527,14 @@
   }
 
   @Override
-  public InetSocketAddress getGatewayAddress() throws UnknownHostException {
-    String host = getGatewayHost();
+  public List<InetSocketAddress> getGatewayAddress() throws UnknownHostException {
+    List<String> hostIps = getGatewayHost();
     int port = getGatewayPort();
-    return new InetSocketAddress( host, port );
+    List<InetSocketAddress> socketAddressList = new ArrayList<>();
+    for (String host : hostIps) {
+      socketAddressList.add(new InetSocketAddress( host, port ));
+    }
+    return socketAddressList;
   }
 
   @Override
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
index 9fe737e..e12b49d 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
@@ -25,6 +25,7 @@
 import java.nio.file.Paths;
 import java.security.KeyStore;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -483,4 +484,18 @@
     config.set("gateway.non.privileged.users", "  guest  ");
     assertThat(config.getNonPrivilegedUsers(), is(new HashSet<>(Arrays.asList("guest"))));
   }
+
+  // KNOX-2779
+  @Test
+  public void testGatewayHost() throws Exception {
+    GatewayConfigImpl config = new GatewayConfigImpl();
+
+    List<String> hosts = new ArrayList<>();
+    hosts.add("0.0.0.0");
+    assertThat(config.getGatewayHost(), is(hosts));
+
+    config.set("gateway.host", "0.0.0.0,127.0.0.1");
+    hosts.add("127.0.0.1");
+    assertThat(config.getGatewayHost(), is(hosts));
+  }
 }
diff --git a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index e493892..96a9a90 100644
--- a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -160,8 +160,10 @@
   }
 
   @Override
-  public String getGatewayHost() {
-    return gatewayHost;
+  public List<String> getGatewayHost() {
+    List<String> hosts = new ArrayList<>();
+    hosts.add(gatewayHost);
+    return hosts;
   }
 
   @Override
@@ -179,8 +181,14 @@
   }
 
   @Override
-  public InetSocketAddress getGatewayAddress() throws UnknownHostException {
-    return new InetSocketAddress( getGatewayHost(), getGatewayPort() );
+  public List<InetSocketAddress> getGatewayAddress() throws UnknownHostException {
+    List<String> hostIps = getGatewayHost();
+    int port = getGatewayPort();
+    List<InetSocketAddress> socketAddressList = new ArrayList<>();
+    for (String host : hostIps) {
+      socketAddressList.add(new InetSocketAddress( host, port ));
+    }
+    return socketAddressList;
   }
 
   @Override
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 68cf6ff..70d0f00 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -141,7 +141,7 @@
 
   String getHadoopConfDir();
 
-  String getGatewayHost();
+  List<String> getGatewayHost();
 
   int getGatewayPort();
 
@@ -167,7 +167,7 @@
 
   String getGatewayDeploymentDir();
 
-  InetSocketAddress getGatewayAddress() throws UnknownHostException;
+  List<InetSocketAddress> getGatewayAddress() throws UnknownHostException;
 
   boolean isSSLEnabled();
 
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
index 0428877..b414b19 100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
@@ -166,7 +166,8 @@
 
       // Try setting up enough of the GatewayServer to support the test...
       GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
-      InetSocketAddress gatewayAddress = new InetSocketAddress(0);
+      List<InetSocketAddress> gatewayAddress = new ArrayList<>();
+      gatewayAddress.add(new InetSocketAddress(0));
       EasyMock.expect(config.getGatewayConfDir()).andReturn(testConfDir.getAbsolutePath()).anyTimes();
       EasyMock.expect(config.getGatewayDataDir()).andReturn(testDataDir.getAbsolutePath()).anyTimes();
       EasyMock.expect(config.getGatewayTopologyDir()).andReturn(testTopoDir.getAbsolutePath()).anyTimes();