Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
691 changes: 348 additions & 343 deletions pom.xml

Large diffs are not rendered by default.

2,145 changes: 1,079 additions & 1,066 deletions src/main/java/com/biasedbit/hotpotato/client/AbstractHttpClient.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.biasedbit.hotpotato.client.HttpRequestContext;
import com.biasedbit.hotpotato.client.timeout.TimeoutManager;
import com.biasedbit.hotpotato.request.HttpRequestFuture;
import com.biasedbit.hotpotato.request.HttpRequestFutureListener;

/**
* Non-pipelining implementation of {@link HttpConnection} interface.
Expand All @@ -51,7 +52,7 @@
*
* @author <a href="http://bruno.biasedbit.com/">Bruno de Carvalho</a>
*/
public class DefaultHttpConnection extends SimpleChannelUpstreamHandler implements HttpConnection {
public class DefaultHttpConnection extends SimpleChannelUpstreamHandler implements HttpConnection, HttpRequestFutureListener {

// configuration defaults -----------------------------------------------------------------------------------------

Expand Down Expand Up @@ -282,6 +283,8 @@ public boolean execute(final HttpRequestContext context) {
this.listener.requestFinished(this, context);
return true;
}

context.getFuture().addListener(this);

synchronized (this.mutex) {
// This implementation only allows one execution at a time. If requests are performed during the period in
Expand Down Expand Up @@ -495,4 +498,11 @@ public String toString() {
.append('(').append(this.host).append(':').append(this.port)
.append(")}").toString();
}

public void operationComplete(HttpRequestFuture future) throws Exception
{
if(future.isCancelled()) {
terminate();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();

if (useSsl) {
SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
SSLEngine engine = SecureChatSslContextFactory.getInstance().getServerContext().createSSLEngine();
engine.setUseClientMode(false);
pipeline.addLast("ssl", new SslHandler(engine));
}
Expand Down Expand Up @@ -342,3 +342,4 @@ public void run() {
});
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,26 @@
public class SecureChatSslContextFactory {

private static final String PROTOCOL = "TLS";
private static final SSLContext SERVER_CONTEXT;
private static final SSLContext CLIENT_CONTEXT;

static {
private final SSLContext serverContext;
private final SSLContext clientContext;

private static final SecureChatSslContextFactory INSTANCE = new SecureChatSslContextFactory();

public static final SecureChatSslContextFactory getInstance()
{
return INSTANCE;
}

public SecureChatSslContextFactory()
{
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}

SSLContext serverContext;
SSLContext clientContext;
SSLContext tmpServerContext;
SSLContext tmpClientContext;
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(SecureChatKeyStore.asInputStream(), SecureChatKeyStore.getKeyStorePassword());
Expand All @@ -55,28 +64,29 @@ public class SecureChatSslContextFactory {
kmf.init(ks, SecureChatKeyStore.getCertificatePassword());

// Initialize the SSLContext to work with our key managers.
serverContext = SSLContext.getInstance(PROTOCOL);
serverContext.init(kmf.getKeyManagers(), SecureChatTrustManagerFactory.getTrustManagers(), null);
tmpServerContext = SSLContext.getInstance(PROTOCOL);
tmpServerContext.init(kmf.getKeyManagers(), SecureChatTrustManagerFactory.getTrustManagers(), null);
} catch (Exception e) {
throw new Error("Failed to initialize the server-side SSLContext", e);
}

try {
clientContext = SSLContext.getInstance(PROTOCOL);
clientContext.init(null, SecureChatTrustManagerFactory.getTrustManagers(), null);
tmpClientContext = SSLContext.getInstance(PROTOCOL);
tmpClientContext.init(null, SecureChatTrustManagerFactory.getTrustManagers(), null);
} catch (Exception e) {
throw new Error("Failed to initialize the client-side SSLContext", e);
}

SERVER_CONTEXT = serverContext;
CLIENT_CONTEXT = clientContext;
serverContext = tmpServerContext;
clientContext = tmpClientContext;
}

public static SSLContext getServerContext() {
return SERVER_CONTEXT;
public SSLContext getServerContext() {
return serverContext;
}

public static SSLContext getClientContext() {
return CLIENT_CONTEXT;
public SSLContext getClientContext() {
return clientContext;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,4 @@ protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
// Unused
}
}

127 changes: 127 additions & 0 deletions src/test/java/com/biasedbit/hotpotato/client/HttpsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.biasedbit.hotpotato.client;

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

import java.io.Closeable;
import java.io.FileInputStream;

import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;

import org.junit.Before;
import org.junit.Test;

import com.biasedbit.hotpotato.response.BodyAsStringProcessor;
import com.biasedbit.hotpotato.request.HttpRequestFuture;
import com.biasedbit.hotpotato.client.DefaultHttpClient;

import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
import org.jboss.netty.handler.codec.http.HttpVersion;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpMethod;

/**
*
*/
public class HttpsTest {
@Test
public void testHttpsRequestSuccess() throws Exception
{
executeHttpsRequest("encrypted.google.com", "/", loadGoogleSslContext(), false);
}

@Test
public void testHttpsRequestFailure() throws Exception
{
// This should fail since we don't have a cert for wellsfargo in our test trustStore...
executeHttpsRequest("www.wellsfargo.com", "/", loadGoogleSslContext(), true);
}

private static SSLContext loadGoogleSslContext() throws Exception
{
String algorithm = "SunX509";
String password = "ez24get";

KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream keyAsStream = null;

try
{
keyAsStream = new FileInputStream("src/test/resources/certs/encrypted.google.com.jks");
keyStore.load(keyAsStream, password.toCharArray());
}
finally
{
closeQuietly(keyAsStream);
}

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);

keyManagerFactory.init(keyStore, password.toCharArray());
trustManagerFactory.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

return sslContext;
}

private static void closeQuietly(Closeable... closeables)
{
if (null != closeables)
{
for (Closeable closeable : closeables)
{
if (null != closeable)
{
try
{
closeable.close();
}
catch (Exception e)
{
// Shhh...
}
}
}
}
}

private static void executeHttpsRequest(final String host, final String resource, final SSLContext sslContext, final boolean shouldFail)
throws Exception
{
DefaultHttpClient client = new DefaultHttpClient();
client.setSSLContext(sslContext);
client.setUseSsl(true);
client.setUseNio(true);
client.init();

DefaultHttpRequest request =
new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, resource);

request.setHeader(HttpHeaders.Names.HOST, host);

HttpRequestFuture future =
client.execute(host, 443, request, new BodyAsStringProcessor()).await();

if (shouldFail)
{
assertThat(future.getResponseStatusCode(), is(not(200)));
}
else
{
assertEquals(200, future.getResponseStatusCode());
}

assertTrue(true);
}
}

Binary file added src/test/resources/certs/encrypted.google.com.jks
Binary file not shown.