package io.searchbox.client.http;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpRequest;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.JestResultHandler;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.indices.Stats;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.transport.Netty4Plugin;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.littleshoot.proxy.HttpFilters;
import org.littleshoot.proxy.HttpFiltersAdapter;
import org.littleshoot.proxy.HttpFiltersSourceAdapter;
import org.littleshoot.proxy.HttpProxyServer;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author cihat keser
*/
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0)
public class JestHttpClientSystemWideProxyIntegrationTest extends ESIntegTestCase {
private static final int PROXY_PORT = 8790;
private AtomicInteger numProxyRequests = new AtomicInteger(0);
private JestClientFactory factory = new JestClientFactory();
private HttpProxyServer server = null;
private static String nonProxyHostsDefault;
private static String proxyHostDefault;
private static String proxyPortDefault;
private static String useSystemProxiesDefault;
@BeforeClass
public static void setupOnce() throws URISyntaxException {
proxyHostDefault = System.getProperty("http.proxyHost");
proxyPortDefault = System.getProperty("http.proxyPort");
useSystemProxiesDefault = System.getProperty("java.net.useSystemProxies");
System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", Integer.toString(PROXY_PORT));
nonProxyHostsDefault = System.getProperty("http.nonProxyHosts");
System.setProperty("http.nonProxyHosts", ""); // we want localhost to go through proxy
System.setProperty("java.net.useSystemProxies", "true");
}
@Before
public void setup() {
server = DefaultHttpProxyServer
.bootstrap()
.withPort(PROXY_PORT)
.withFiltersSource(new HttpFiltersSourceAdapter() {
public HttpFilters filterRequest(HttpRequest originalRequest, ChannelHandlerContext ctx) {
return new HttpFiltersAdapter(originalRequest) {
@Override
public void proxyToServerRequestSent() {
numProxyRequests.incrementAndGet();
}
};
}
}).start();
}
@After
public void destroy() {
if (server != null) server.stop();
}
@AfterClass
public static void destroyOnce() {
rollbackSystemProperty("http.proxyHost", proxyHostDefault);
rollbackSystemProperty("http.proxyPort", proxyPortDefault);
rollbackSystemProperty("http.nonProxyHosts", nonProxyHostsDefault);
rollbackSystemProperty("java.net.useSystemProxies", useSystemProxiesDefault);
}
private static void rollbackSystemProperty(String key, String value) {
if (value == null) {
System.clearProperty(key);
} else {
System.setProperty(key, value);
}
}
@Test
public void testConnectionThroughDefaultProxy() throws IOException, ExecutionException, InterruptedException {
internalCluster().ensureAtLeastNumDataNodes(1);
assertEquals("All nodes in cluster should have HTTP endpoint exposed", 1, cluster().httpAddresses().length);
// test sync execution
factory.setHttpClientConfig(new HttpClientConfig
.Builder("http://localhost:" + cluster().httpAddresses()[0].getPort())
.build());
JestHttpClient jestClient = (JestHttpClient) factory.getObject();
assertNotNull(jestClient);
JestResult result = jestClient.execute(new Stats.Builder().build());
assertTrue(result.getErrorMessage(), result.isSucceeded());
assertEquals(1, numProxyRequests.intValue());
jestClient.shutdownClient();
// test async execution
factory.setHttpClientConfig(new HttpClientConfig
.Builder("http://localhost:" + cluster().httpAddresses()[0].getPort())
.multiThreaded(true)
.build());
jestClient = (JestHttpClient) factory.getObject();
assertNotNull(jestClient);
final CountDownLatch actionExecuted = new CountDownLatch(1);
jestClient.executeAsync(new Stats.Builder().build(), new JestResultHandler<JestResult>() {
@Override
public void completed(JestResult result) {
actionExecuted.countDown();
}
@Override
public void failed(Exception ex) {
throw new RuntimeException(ex);
}
});
boolean finishedAsync = actionExecuted.await(2, TimeUnit.SECONDS);
if (!finishedAsync) {
fail("Execution took too long to complete");
}
assertEquals(2, numProxyRequests.intValue());
jestClient.shutdownClient();
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_TYPE_KEY, Netty4Plugin.NETTY_HTTP_TRANSPORT_NAME)
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singletonList(Netty4Plugin.class);
}
}