I sucessfully put of to actually submit that question until I eventually managed to get it working myself (took me long enough) :-).
Pretty much EYERYTHING is somehow abstracted away in this library and like EVERYTHING can be configured. Except Sockets. The only thing which seems to lack any abstraction in apache http client. It took me forever to try to get the lib work just on streams and not on Sockets until I finally gave up and implemented my own "sockets".
But then it was quite simple: In the HttpClientBuilder
a connectionManager
can be set which instantiates sockets and connects them. You can implement your own connection manager and return a socket with an overriden getOutputStream
/getInputStream
method and then you can work with those streams that you created. Don't forget to also override the connect method, because we don't want to create any network activity here.
Here is an example TestNG-Test which demonstrates the behavior and on which you can surely built upon.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.testng.annotations.Test;
public class InterruptedConnectionTest {
private static final InputStream EMPTY_INPUT_STREAM = new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
};
private static final ConnectionSocketFactory FAILURE_SOCKET_FACTORY = new ConnectionSocketFactory() {
@Override
public Socket createSocket(HttpContext context) throws IOException {
final InputStream in = EMPTY_INPUT_STREAM;
final OutputStream out = new FailureOutputStream(10);
return new Socket() {
@Override
public InputStream getInputStream() throws IOException {
return in;
}
@Override
public OutputStream getOutputStream() throws IOException {
return out;
}
};
}
@Override
public Socket connectSocket(int connectTimeout, Socket sock,
HttpHost host, InetSocketAddress remoteAddress,
InetSocketAddress localAddress, HttpContext context)
throws IOException {
return sock; // do nothing
}
};
@Test(expectedExceptions = MockIOException.class)
public void executingRequest_throwsException() throws Exception {
HttpClient httpClient = HttpClientBuilder
.create()
.setConnectionManager(new BasicHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", FAILURE_SOCKET_FACTORY)
.build()))
.build();
httpClient.execute(new HttpGet("http://localhost/some/path"));
}
private static class FailureOutputStream extends OutputStream {
private int bytesRead = 0;
private final int failByte;
private FailureOutputStream(int failByte) {
super();
this.failByte = failByte;
}
@Override
public void write(int b) throws IOException {
++bytesRead;
if (bytesRead >= failByte) {
throw new MockIOException("Mock error after having having read <" + bytesRead + "> bytes");
}
}
}
private static class MockIOException extends IOException {
public MockIOException(String message) {
super(message);
}
}
}