Repository: docker-java/docker-java
Pull request #125 (2015-01-14 19:43:35)

Unixsocket rebased

gesellix: Just for the record I'd like mention that @alexkamp initially created the code in https://github.com/gesellix-docker/docker-java/commit/a230b219d518f7c0c2b61e2d0def028958eaaa6e and only contains some modifications to make ssl work with the ApacheConnector.
When this PR is merged, #20 can be closed.

marcuslinke: @gesellix Sadly i can't get all integration tests running with it. ```EventsCmdImplTest.testEventStreaming``` hangs forever here. Any suggestions?
gesellix: @marcuslinke in which environment? http, https, boot2docker, unix? ... too many choices ;)  can you post a stacktrace?

marcuslinke: @gesellix Oh, sorry. I meant testing against boot2docker/MacOS with https connection. ```EventsCmdImplTest.testEventStreaming``` just hangs forever. No stacktrace. 
marcuslinke: This may due to latest changes as i merged your branch locally. Maybe i'm able to investigate this in the evening...
gesellix: @marcuslinke if you prefer, I can apply another rebase/squash based on the current master. I can investigate this evening, too, but I would prefer if you could try on your environment (boot2docker/mac/https).

gesellix: @marcuslinke looks like it's only an InputStream which isn't fully read in a test... I'm going to apply a fix and cleanup this PR


Patch:
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..a96e5522
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+.git/
+target/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..eea3db56
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,18 @@
+FROM java:7
+MAINTAINER https://github.com/docker-java/docker-java
+
+ENV HOME /root
+ENV M2_HOME /opt/apache-maven-3.0.5
+
+RUN wget http://www.eu.apache.org/dist/maven/maven-3/3.0.5/binaries/apache-maven-3.0.5-bin.tar.gz -O /tmp/apache-maven-3.0.5-bin.tar.gz \
+    && cd /tmp \
+    && tar xzf apache-maven-3.0.5-bin.tar.gz \
+    && mkdir -p /opt \
+    && mv apache-maven-3.0.5 /opt \
+    && rm apache-maven-3.0.5-bin.tar.gz
+
+WORKDIR /project
+ADD . /project/
+
+#ENTRYPOINT $M2_HOME/bin/mvn
+CMD $M2_HOME/bin/mvn verify
diff --git a/pom.xml b/pom.xml
index 0b85dc42..1e6a477e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,13 @@
 		</developer>
 	</developers>
 
+	<repositories>
+		<repository>
+			<id>jcenter</id>
+			<url>http://jcenter.bintray.com</url>
+		</repository>
+	</repositories>
+
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -64,6 +71,7 @@
 		<jnr.unixsocket.version>0.3</jnr.unixsocket.version>
 		<guava.version>18.0</guava.version>
 		<bouncycastle.version>1.51</bouncycastle.version>
+		<unix-socket-factory.version>2014-11-16T14-41-27</unix-socket-factory.version>
 
 		<!--test dependencies -->
 		<version.logback>1.0.1</version.logback>
@@ -93,12 +101,23 @@
 		<!-- <artifactId>jersey-jetty-connector</artifactId> -->
 		<!-- <version>${jersey.version}</version> -->
 		<!-- </dependency> -->
+		<dependency>
+	 		<groupId>org.glassfish.jersey.connectors</groupId>
+			<artifactId>jersey-apache-connector</artifactId>
+			<version>${jersey.version}</version>
+		</dependency>
 		<dependency>
 			<groupId>org.glassfish.jersey.core</groupId>
 			<artifactId>jersey-client</artifactId>
 			<version>${jersey.version}</version>
 		</dependency>
 
+		<dependency>
+			<groupId>de.gesellix</groupId>
+			 <artifactId>unix-socket-factory</artifactId>
+		 	<version>${unix-socket-factory.version}</version>
+		</dependency>
+
 		<dependency>
 			<groupId>org.apache.commons</groupId>
 			<artifactId>commons-compress</artifactId>
diff --git a/src/main/java/com/github/dockerjava/api/command/EventCallback.java b/src/main/java/com/github/dockerjava/api/command/EventCallback.java
index 45ac34dc..18b8669e 100644
--- a/src/main/java/com/github/dockerjava/api/command/EventCallback.java
+++ b/src/main/java/com/github/dockerjava/api/command/EventCallback.java
@@ -9,4 +9,5 @@ public interface EventCallback {
     public void onEvent(Event event);
     public void onException(Throwable throwable);
     public void onCompletion(int numEvents);
+    public boolean isReceiving();
 }
diff --git a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java
index 87307bb5..42c49bce 100644
--- a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java
+++ b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java
@@ -8,7 +8,7 @@ public class AuthConfig {
     /**
      * For backwards compatibility. Make sure you update the properties if you change this.
      *
-     * @see /docker.io.properties
+     * @see "/docker.io.properties"
      */
     public static final String DEFAULT_SERVER_ADDRESS = "https://index.docker.io/v1/";
 
diff --git a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
index c90c62cb..21e5778f 100644
--- a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
+++ b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
@@ -33,6 +33,9 @@ public class DockerClientConfig implements Serializable {
     private static final String DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY = "docker.io.enableLoggingFilter";
     private static final String DOCKER_IO_DOCKER_CERT_PATH_PROPERTY = "docker.io.dockerCertPath";
     private static final String DOCKER_IO_DOCKER_CFG_PATH_PROPERTY = "docker.io.dockerCfgPath";
+    // connection pooling properties
+    private static final String DOCKER_IO_MAX_PER_ROUTE_PROPERTY = "docker.io.perRouteConnections";
+    private static final String DOCKER_IO_MAX_TOTAL_PROPERTY = "docker.io.totalConnections";
     /**
      * A map from the environment name to the interval name.
      */
@@ -49,13 +52,18 @@ public class DockerClientConfig implements Serializable {
             .put("DOCKER_CFG_PATH", DOCKER_IO_DOCKER_CFG_PATH_PROPERTY)
             .build();
     private static final String DOCKER_IO_PROPERTIES_PROPERTY = "docker.io.properties";
-    private final URI uri;
+    private URI uri;
     private final String version, username, password, email, serverAddress, dockerCfgPath;
     private final Integer readTimeout;
     private final boolean loggingFilterEnabled;
     private final SSLConfig sslConfig;
+    
+    private final int maxTotalConnections;
+    private final int maxPerRouteConnections;
 
-    DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress, String dockerCfgPath, Integer readTimeout, boolean loggingFilterEnabled, SSLConfig sslConfig) {
+    DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress,
+                       String dockerCfgPath, Integer readTimeout, boolean loggingFilterEnabled, SSLConfig sslConfig,
+                       int maxTotalConns, int maxPerRouteConns) {
         this.uri = uri;
         this.version = version;
         this.username = username;
@@ -66,6 +74,8 @@ public class DockerClientConfig implements Serializable {
         this.readTimeout = readTimeout;
         this.loggingFilterEnabled = loggingFilterEnabled;
         this.sslConfig = sslConfig;
+        this.maxTotalConnections = maxTotalConns;
+        this.maxPerRouteConnections = maxPerRouteConns;
     }
 
     private static Properties loadIncludedDockerProperties(Properties systemProperties) {
@@ -194,6 +204,10 @@ public class DockerClientConfig implements Serializable {
         return uri;
     }
 
+    public void setUri(URI uri) {
+		this.uri = uri;
+	}
+
     public String getVersion() {
         return version;
     }
@@ -329,7 +343,7 @@ public class DockerClientConfig implements Serializable {
     public static class DockerClientConfigBuilder {
         private URI uri;
         private String version, username, password, email, serverAddress, dockerCfgPath;
-        private Integer readTimeout;
+        private Integer readTimeout, maxTotalConnections, maxPerRouteConnections;
         private boolean loggingFilterEnabled;
         private SSLConfig sslConfig;
 
@@ -349,7 +363,10 @@ public class DockerClientConfig implements Serializable {
                     .withReadTimeout(Integer.valueOf(p.getProperty(DOCKER_IO_READ_TIMEOUT_PROPERTY, "0")))
                     .withLoggingFilter(Boolean.valueOf(p.getProperty(DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY, "true")))
                     .withDockerCertPath(p.getProperty(DOCKER_IO_DOCKER_CERT_PATH_PROPERTY))
-                    .withDockerCfgPath(p.getProperty(DOCKER_IO_DOCKER_CFG_PATH_PROPERTY));
+                    .withDockerCfgPath(p.getProperty(DOCKER_IO_DOCKER_CFG_PATH_PROPERTY))
+                    .withMaxPerRouteConnections(Integer.valueOf(p.getProperty(DOCKER_IO_MAX_PER_ROUTE_PROPERTY, "2")))
+                    .withMaxTotalConnections(Integer.valueOf(p.getProperty(DOCKER_IO_MAX_TOTAL_PROPERTY, "20")))
+                    ;
         }
 
         public final DockerClientConfigBuilder withUri(String uri) {
@@ -387,6 +404,16 @@ public class DockerClientConfig implements Serializable {
             this.readTimeout = readTimeout;
             return this;
         }
+        
+        public final DockerClientConfigBuilder withMaxTotalConnections(Integer maxTotalConnections) {
+            this.maxTotalConnections = maxTotalConnections;
+            return this;
+        }
+        
+        public final DockerClientConfigBuilder withMaxPerRouteConnections(Integer maxPerRouteConnections) {
+            this.maxPerRouteConnections = maxPerRouteConnections;
+            return this;
+        }
 
         public final DockerClientConfigBuilder withLoggingFilter(boolean loggingFilterEnabled) {
             this.loggingFilterEnabled = loggingFilterEnabled;
@@ -420,8 +447,18 @@ public class DockerClientConfig implements Serializable {
                     dockerCfgPath,
                     readTimeout,
                     loggingFilterEnabled,
-                    sslConfig
+                    sslConfig,
+                    maxTotalConnections,
+                    maxPerRouteConnections
             );
         }
     }
+
+    public int getMaxTotalConnections() {
+      return maxTotalConnections;
+    }
+
+    public int getMaxPerRoutConnections() {
+      return maxPerRouteConnections;
+    }
 }
diff --git a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java
index cee364e0..6b829abd 100644
--- a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java
+++ b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java
@@ -8,18 +8,15 @@ import java.io.IOException;
 import java.io.InputStream;
 
 import com.github.dockerjava.api.DockerClient;
-import com.github.dockerjava.api.DockerClientException;
 import com.github.dockerjava.api.command.*;
 import com.github.dockerjava.api.model.AuthConfig;
-import com.github.dockerjava.core.NameParser.HostnameReposName;
-import com.github.dockerjava.core.NameParser.ReposTag;
 import com.github.dockerjava.core.command.*;
 import com.google.common.base.Preconditions;
 
 /**
  * @author Konstantin Pelykh (kpelykh@gmail.com)
  * 
- * @see https://github.com/docker/docker/blob/master/api/client/commands.go
+ * @see "https://github.com/docker/docker/blob/master/api/client/commands.go"
  */
 public class DockerClientImpl implements Closeable, DockerClient {
 
diff --git a/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java b/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java
index ef57a0de..6415d0c1 100644
--- a/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java
+++ b/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java
@@ -1,19 +1,16 @@
 package com.github.dockerjava.core;
 
+import com.github.dockerjava.api.DockerClientException;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
-
-import com.github.dockerjava.api.DockerClientException;
-
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.glassfish.jersey.SslConfigurator;
 
+import javax.net.ssl.SSLContext;
 import java.io.Serializable;
 import java.security.KeyStore;
 import java.security.Security;
 
-import javax.net.ssl.SSLContext;
-
 /**
  * SSL Config from local files.
  */
@@ -41,9 +38,6 @@ public class LocalDirectorySSLConfig implements SSLConfig, Serializable {
 
         Security.addProvider(new BouncyCastleProvider());
 
-        KeyStore keyStore = CertificateUtils.createKeyStore(dockerCertPath);
-        KeyStore trustStore = CertificateUtils.createTrustStore(dockerCertPath);
-
         // properties acrobatics not needed for java > 1.6
         String httpProtocols = System.getProperty("https.protocols");
         System.setProperty("https.protocols", "TLSv1");
@@ -52,9 +46,9 @@ public class LocalDirectorySSLConfig implements SSLConfig, Serializable {
           System.setProperty("https.protocols", httpProtocols);
         }
 
-        sslConfig.keyStore(keyStore);
+        sslConfig.keyStore(CertificateUtils.createKeyStore(dockerCertPath));
         sslConfig.keyStorePassword("docker");
-        sslConfig.trustStore(trustStore);
+        sslConfig.trustStore(CertificateUtils.createTrustStore(dockerCertPath));
 
         return sslConfig.createSSLContext();
 
diff --git a/src/main/java/com/github/dockerjava/core/SSLConfig.java b/src/main/java/com/github/dockerjava/core/SSLConfig.java
index 21024c4f..ab639489 100644
--- a/src/main/java/com/github/dockerjava/core/SSLConfig.java
+++ b/src/main/java/com/github/dockerjava/core/SSLConfig.java
@@ -1,9 +1,6 @@
 package com.github.dockerjava.core;
 
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
+import java.security.*;
 
 import javax.net.ssl.SSLContext;
 
diff --git a/src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java b/src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java
new file mode 100644
index 00000000..a4adb1bb
--- /dev/null
+++ b/src/main/java/com/github/dockerjava/jaxrs/ApacheUnixSocket.java
@@ -0,0 +1,327 @@
+package com.github.dockerjava.jaxrs;
+/*
+ * Copyright (c) 2014 Spotify AB.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+
+
+import com.google.common.collect.Queues;
+
+import org.newsclub.net.unix.AFUNIXSocket;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+import java.util.Queue;
+
+/**
+ * Provides a socket that wraps an org.newsclub.net.unix.AFUNIXSocket and delays setting options
+ * until the socket is connected. This is necessary because the Apache HTTP client attempts to
+ * set options prior to connecting the socket, which doesn't work for Unix sockets since options
+ * are being set on the underlying file descriptor. Until the socket is connected, the file
+ * descriptor doesn't exist.
+ *
+ * This class also noop's any calls to setReuseAddress, which is called by the Apache client but
+ * isn't supported by AFUnixSocket.
+ */
+public class ApacheUnixSocket extends Socket {
+
+  private final AFUNIXSocket inner;
+
+  private final Queue<SocketOptionSetter> optionsToSet = Queues.newArrayDeque();
+
+  public ApacheUnixSocket() throws IOException {
+    this.inner = AFUNIXSocket.newInstance();
+  }
+
+  @Override
+  public void connect(final SocketAddress endpoint) throws IOException {
+    inner.connect(endpoint);
+    setAllSocketOptions();
+  }
+
+  @Override
+  public void connect(final SocketAddress endpoint, final int timeout) throws IOException {
+    inner.connect(endpoint, timeout);
+    setAllSocketOptions();
+  }
+
+  @Override
+  public void bind(final SocketAddress bindpoint) throws IOException {
+    inner.bind(bindpoint);
+    setAllSocketOptions();
+  }
+
+  @Override
+  public InetAddress getInetAddress() {
+    return inner.getInetAddress();
+  }
+
+  @Override
+  public InetAddress getLocalAddress() {
+    return inner.getLocalAddress();
+  }
+
+  @Override
+  public int getPort() {
+    return inner.getPort();
+  }
+
+  @Override
+  public int getLocalPort() {
+    return inner.getLocalPort();
+  }
+
+  @Override
+  public SocketAddress getRemoteSocketAddress() {
+    return inner.getRemoteSocketAddress();
+  }
+
+  @Override
+  public SocketAddress getLocalSocketAddress() {
+    return inner.getLocalSocketAddress();
+  }
+
+  @Override
+  public SocketChannel getChannel() {
+    return inner.getChannel();
+  }
+
+  @Override
+  public InputStream getInputStream() throws IOException {
+    return inner.getInputStream();
+  }
+
+  @Override
+  public OutputStream getOutputStream() throws IOException {
+    return inner.getOutputStream();
+  }
+
+  private void setSocketOption(final SocketOptionSetter s) throws SocketException {
+    if (inner.isConnected()) {
+      s.run();
+    } else {
+      if (!optionsToSet.offer(s)) {
+        throw new SocketException("Failed to queue option");
+      }
+    }
+  }
+
+  private void setAllSocketOptions() throws SocketException {
+    for (SocketOptionSetter s : optionsToSet) {
+      s.run();
+    }
+  }
+
+  @Override
+  public void setTcpNoDelay(final boolean on) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setTcpNoDelay(on);
+      }
+    });
+  }
+
+  @Override
+  public boolean getTcpNoDelay() throws SocketException {
+    return inner.getTcpNoDelay();
+  }
+
+  @Override
+  public void setSoLinger(final boolean on, final int linger) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setSoLinger(on, linger);
+      }
+    });
+  }
+
+  @Override
+  public int getSoLinger() throws SocketException {
+    return inner.getSoLinger();
+  }
+
+  @Override
+  public void sendUrgentData(final int data) throws IOException {
+    inner.sendUrgentData(data);
+  }
+
+  @Override
+  public void setOOBInline(final boolean on) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setOOBInline(on);
+      }
+    });
+  }
+
+  @Override
+  public boolean getOOBInline() throws SocketException {
+    return inner.getOOBInline();
+  }
+
+  @Override
+  public synchronized void setSoTimeout(final int timeout) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setSoTimeout(timeout);
+      }
+    });
+  }
+
+  @Override
+  public synchronized int getSoTimeout() throws SocketException {
+    return inner.getSoTimeout();
+  }
+
+  @Override
+  public synchronized void setSendBufferSize(final int size) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setSendBufferSize(size);
+      }
+    });
+  }
+
+  @Override
+  public synchronized int getSendBufferSize() throws SocketException {
+    return inner.getSendBufferSize();
+  }
+
+  @Override
+  public synchronized void setReceiveBufferSize(final int size) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setReceiveBufferSize(size);
+      }
+    });
+  }
+
+  @Override
+  public synchronized int getReceiveBufferSize() throws SocketException {
+    return inner.getReceiveBufferSize();
+  }
+
+  @Override
+  public void setKeepAlive(final boolean on) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setKeepAlive(on);
+      }
+    });
+  }
+
+  @Override
+  public boolean getKeepAlive() throws SocketException {
+    return inner.getKeepAlive();
+  }
+
+  @Override
+  public void setTrafficClass(final int tc) throws SocketException {
+    setSocketOption(new SocketOptionSetter() {
+      @Override
+      public void run() throws SocketException {
+        inner.setTrafficClass(tc);
+      }
+    });
+  }
+
+  @Override
+  public int getTrafficClass() throws SocketException {
+    return inner.getTrafficClass();
+  }
+
+  @Override
+  public void setReuseAddress(final boolean on) throws SocketException {
+    // not supported: Apache client tries to set it, but we want to just ignore it
+  }
+
+  @Override
+  public boolean getReuseAddress() throws SocketException {
+    return inner.getReuseAddress();
+  }
+
+  @Override
+  public synchronized void close() throws IOException {
+    inner.close();
+  }
+
+  @Override
+  public void shutdownInput() throws IOException {
+    inner.shutdownInput();
+  }
+
+  @Override
+  public void shutdownOutput() throws IOException {
+    inner.shutdownOutput();
+  }
+
+  @Override
+  public String toString() {
+    return inner.toString();
+  }
+
+  @Override
+  public boolean isConnected() {
+    return inner.isConnected();
+  }
+
+  @Override
+  public boolean isBound() {
+    return inner.isBound();
+  }
+
+  @Override
+  public boolean isClosed() {
+    return inner.isClosed();
+  }
+
+  @Override
+  public boolean isInputShutdown() {
+    return inner.isInputShutdown();
+  }
+
+  @Override
+  public boolean isOutputShutdown() {
+    return inner.isOutputShutdown();
+  }
+
+  @Override
+  public void setPerformancePreferences(final int connectionTime, final int latency,
+                                        final int bandwidth) {
+    inner.setPerformancePreferences(connectionTime, latency, bandwidth);
+  }
+
+  interface SocketOptionSetter {
+    void run() throws SocketException;
+  }
+}
diff --git a/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java
index 0a657ed9..2b7059b3 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/ContainerDiffCmdExec.java
@@ -26,7 +26,8 @@ public class ContainerDiffCmdExec extends AbstrDockerCmdExec<ContainerDiffCmd, L
 		WebTarget webResource = getBaseResource().path("/containers/{id}/changes").resolveTemplate("id", command.getContainerId());
 		
 		LOGGER.trace("GET: {}", webResource);
-		return webResource.request().accept(MediaType.APPLICATION_JSON).get(new GenericType<List<ChangeLog>>() {
+		return webResource.request().accept(MediaType.APPLICATION_JSON)
+				.get(new GenericType<List<ChangeLog>>() {
         });
 	}
 
diff --git a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
index 525e4a58..c91b0d56 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
@@ -8,7 +8,14 @@ import com.github.dockerjava.jaxrs.util.JsonClientFilter;
 import com.github.dockerjava.jaxrs.util.ResponseStatusExceptionFilter;
 import com.github.dockerjava.jaxrs.util.SelectiveLoggingFilter;
 import com.google.common.base.Preconditions;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.apache.connector.ApacheClientProperties;
+import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
 import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.client.ClientProperties;
 
@@ -17,6 +24,7 @@ import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.WebTarget;
 import java.io.IOException;
+import java.net.URI;
 import java.util.logging.Logger;
 
 public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory {
@@ -30,6 +38,7 @@ public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory {
         Preconditions.checkNotNull(dockerClientConfig, "config was not specified");
 
         ClientConfig clientConfig = new ClientConfig();
+        clientConfig.connectorProvider(new ApacheConnectorProvider());
         clientConfig.property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
 
         clientConfig.register(ResponseStatusExceptionFilter.class);
@@ -45,20 +54,31 @@ public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory {
             clientConfig.property(ClientProperties.READ_TIMEOUT, readTimeout);
         }
 
-        ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig);
+        URI originalUri = dockerClientConfig.getUri();
 
+        SSLContext sslContext;
         try {
-            SSLContext ssl = dockerClientConfig.getSslConfig().getSSLContext();
-
-            if (ssl != null)
-                clientBuilder.sslContext(ssl);
+            sslContext = dockerClientConfig.getSslConfig().getSSLContext();
         } catch(Exception ex) {
             throw new DockerClientException("Error in SSL Configuration", ex);
         }
 
+        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(getSchemeRegistry(originalUri, sslContext));
+        connManager.setMaxTotal(dockerClientConfig.getMaxTotalConnections());
+        connManager.setDefaultMaxPerRoute(dockerClientConfig.getMaxPerRoutConnections());
+        clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connManager);
+
+        ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig);
+
+        if (sslContext != null) {
+            clientBuilder.sslContext(sslContext);
+        }
 
         client = clientBuilder.build();
 
+        if (originalUri.getScheme().equals("unix")) {
+            dockerClientConfig.setUri(UnixConnectionSocketFactory.sanitizeUri(originalUri));
+        }
         WebTarget webResource = client.target(dockerClientConfig.getUri());
 
         if (dockerClientConfig.getVersion() == null || dockerClientConfig.getVersion().isEmpty()) {
@@ -66,9 +86,18 @@ public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory {
         } else {
             baseResource = webResource.path("v" + dockerClientConfig.getVersion());
         }
-
     }
 
+    private org.apache.http.config.Registry<ConnectionSocketFactory> getSchemeRegistry(final URI originalUri, SSLContext sslContext) {
+      RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create();
+      registryBuilder.register("http", PlainConnectionSocketFactory.getSocketFactory());
+      if (sslContext != null) {
+        registryBuilder.register("https", new SSLConnectionSocketFactory(sslContext));
+      }
+      registryBuilder.register("unix", new UnixConnectionSocketFactory(originalUri));
+      return registryBuilder.build();
+      }
+
     protected WebTarget getBaseResource() {
         Preconditions.checkNotNull(baseResource, "Factory not initialized. You probably forgot to call init()!");
         return baseResource;
diff --git a/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java
index 545d7db9..ffd757e9 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/EventsCmdExec.java
@@ -67,7 +67,7 @@ public class EventsCmdExec extends AbstrDockerCmdExec<EventsCmd, ExecutorService
                 response = webTarget.request().get(Response.class);
                 InputStream inputStream = response.readEntity(InputStream.class);
                 JsonParser jp = JSON_FACTORY.createParser(inputStream);
-                while (jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed()) {
+                while (jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed() && eventCallback.isReceiving()) {
                     eventCallback.onEvent(OBJECT_MAPPER.readValue(jp, Event.class));
                     numEvents++;
                 }
diff --git a/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java
index 7f45bdda..7a479ce2 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/RemoveContainerCmdExec.java
@@ -23,8 +23,8 @@ public class RemoveContainerCmdExec extends AbstrDockerCmdExec<RemoveContainerCm
 				.queryParam("force", command.hasForceEnabled() ? "1" : "0");
 		
 		LOGGER.trace("DELETE: {}", webResource);
-		String response = webResource.request().accept(MediaType.APPLICATION_JSON).delete(String.class);
-		LOGGER.trace("Response: {}", response);
+		/*String response = */webResource.request().accept(MediaType.APPLICATION_JSON).delete().close();
+//		LOGGER.trace("Response: {}", response);
 
 		return null;
 	}
diff --git a/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java b/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java
index 54fb327b..6bfeecd7 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/RemoveImageCmdExec.java
@@ -23,7 +23,7 @@ public class RemoveImageCmdExec extends AbstrDockerCmdExec<RemoveImageCmd, Void>
 				.queryParam("noprune", command.hasNoPruneEnabled() ? "1" : "0");
 
 		LOGGER.trace("DELETE: {}", webResource);
-		webResource.request().delete(Response.class);
+		webResource.request().delete().close();
 		
 		return null;
 	}
diff --git a/src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java b/src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java
new file mode 100644
index 00000000..4b6cfbba
--- /dev/null
+++ b/src/main/java/com/github/dockerjava/jaxrs/UnixConnectionSocketFactory.java
@@ -0,0 +1,85 @@
+package com.github.dockerjava.jaxrs;
+/*
+ * Copyright (c) 2014 Spotify AB.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+
+
+import org.apache.http.HttpHost;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.protocol.HttpContext;
+import org.newsclub.net.unix.AFUNIXSocketAddress;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+
+/**
+ * Provides a ConnectionSocketFactory for connecting Apache HTTP clients to Unix sockets.
+ */
+@Immutable
+public class UnixConnectionSocketFactory implements ConnectionSocketFactory {
+
+  private File socketFile;
+
+  public UnixConnectionSocketFactory(final URI socketUri) {
+    super();
+
+    final String filename = socketUri.toString()
+        .replaceAll("^unix:///", "unix://localhost/")
+        .replaceAll("^unix://localhost", "");
+
+    this.socketFile = new File(filename);
+  }
+
+  public static URI sanitizeUri(final URI uri) {
+    if (uri.getScheme().equals("unix")) {
+      return URI.create("unix://localhost:80");
+    } else {
+      return uri;
+    }
+  }
+
+  @Override
+  public Socket createSocket(final HttpContext context) throws IOException {
+    return new ApacheUnixSocket();
+  }
+
+  @Override
+  public Socket connectSocket(final int connectTimeout,
+                              final Socket socket,
+                              final HttpHost host,
+                              final InetSocketAddress remoteAddress,
+                              final InetSocketAddress localAddress,
+                              final HttpContext context) throws IOException {
+    try {
+      socket.connect(new AFUNIXSocketAddress(socketFile), connectTimeout);
+    } catch (SocketTimeoutException e) {
+      throw new ConnectTimeoutException(e, null, remoteAddress.getAddress());
+    }
+
+    return socket;
+  }
+}
diff --git a/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java b/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java
index 61d97f93..42158e01 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/util/ResponseStatusExceptionFilter.java
@@ -2,6 +2,7 @@ package com.github.dockerjava.jaxrs.util;
 
 import java.io.EOFException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.Charset;
 
 import javax.ws.rs.client.ClientRequestContext;
@@ -63,7 +64,9 @@ public class ResponseStatusExceptionFilter implements ClientResponseFilter {
 	        if (contentLength != -1) {
 	            byte[] buffer = new byte[contentLength];
 	            try {
-	                IOUtils.readFully(responseContext.getEntityStream(), buffer);
+	                InputStream entityStream = responseContext.getEntityStream();
+                  IOUtils.readFully(entityStream, buffer);
+                  entityStream.close();
 	            }
 	            catch (EOFException e) {
 	                return null;


Test patch:
diff --git a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java
index 3ed64d9a..71bfb930 100644
--- a/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java
+++ b/src/test/java/com/github/dockerjava/client/AbstractDockerClientTest.java
@@ -33,7 +33,6 @@ public abstract class AbstractDockerClientTest extends Assert {
 
 	public static final Logger LOG = LoggerFactory
 			.getLogger(AbstractDockerClientTest.class);
-    public static final String DOCKER_JAVA = "dockerjava";
 
     protected DockerClient dockerClient;
 
@@ -120,7 +119,8 @@ public abstract class AbstractDockerClientTest extends Assert {
 				logwriter.write(line + (itr.hasNext() ? "\n" : ""));
 				//LOG.info("line: "+line);
 			}
-
+			response.close();
+			
 			return logwriter.toString();
 		} catch (IOException e) {
 			throw new RuntimeException(e);
@@ -150,7 +150,7 @@ public abstract class AbstractDockerClientTest extends Assert {
 			ds = new DatagramSocket(port);
 			ds.setReuseAddress(true);
 			return true;
-		} catch (IOException e) {
+		} catch (IOException ignored) {
 		} finally {
 			if (ds != null) {
 				ds.close();
diff --git a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java
index e452e300..4611f430 100644
--- a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java
+++ b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java
@@ -16,7 +16,7 @@ public class DockerClientConfigTest {
     public static final DockerClientConfig EXAMPLE_CONFIG = newExampleConfig();
 
     private static DockerClientConfig newExampleConfig() {
-        return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flam", 877, false, new LocalDirectorySSLConfig("flim"));
+        return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flam", 877, false, new LocalDirectorySSLConfig("flim"), 20, 2);
     }
 
     @Test
@@ -36,6 +36,8 @@ public class DockerClientConfigTest {
         // given docker host in env
         Map<String, String> env = new HashMap<String, String>();
         env.put("DOCKER_HOST", "tcp://baz:8768");
+        // and it looks to be SSL disabled
+        env.remove("DOCKER_CERT_PATH");
 
         // when you build a config
         DockerClientConfig config = buildConfig(env, new Properties());
@@ -82,7 +84,9 @@ public class DockerClientConfigTest {
         // given docker host in env
         Map<String, String> env = new HashMap<String, String>(System.getenv());
         env.put("DOCKER_HOST", "tcp://bar:8768");
-        // and it looks to be SSL enabled
+        // and it looks to be SSL disabled
+        env.remove("DOCKER_CERT_PATH");
+        // and it has an invalid TLS_VERIFY value
         env.put("DOCKER_TLS_VERIFY", "any value different from '1'");
 
         // when you build a config
@@ -92,6 +96,24 @@ public class DockerClientConfigTest {
         assertEquals(config.getUri(), URI.create("http://bar:8768"));
     }
 
+    @Test
+    public void environmentDockerHostWithInvalidTlsVerifyButWithCertPath() throws Exception {
+
+        // given docker host in env
+        Map<String, String> env = new HashMap<String, String>(System.getenv());
+        env.put("DOCKER_HOST", "tcp://bar:8768");
+        // and it looks to be SSL enabled
+        env.put("DOCKER_CERT_PATH", "any value");
+        // and it has an invalid TLS_VERIFY value
+        env.put("DOCKER_TLS_VERIFY", "any value different from '1'");
+
+        // when you build a config
+        DockerClientConfig config = buildConfig(env, new Properties());
+
+        // then the URL is that value with "tcp" changed to "https"
+        assertEquals(config.getUri(), URI.create("https://bar:8768"));
+    }
+
     @Test
     public void environment() throws Exception {
 
diff --git a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java
index a91fa109..1f5604fe 100644
--- a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java
@@ -10,7 +10,7 @@ public class DockerClientImplTest {
     @Test
     public void configuredInstanceAuthConfig() throws Exception {
         // given a config with null serverAddress
-        DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null,  0, false, null);
+        DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null,  0, false, null, 20, 2);
         DockerClientImpl dockerClient = DockerClientImpl.getInstance(dockerClientConfig);
 
         // when we get the auth config
diff --git a/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java b/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java
index b556a7e5..215926a5 100644
--- a/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java
+++ b/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java
@@ -3,7 +3,6 @@
  */
 package com.github.dockerjava.core;
 
-import java.io.File;
 import java.io.IOException;
 
 import junit.framework.Assert;
@@ -19,7 +18,7 @@ public class GoLangFileMatchTest {
         String pattern = testCase.pattern;
         String s = testCase.s;
         if (GoLangFileMatch.IS_WINDOWS) {
-            if (pattern.indexOf('\\') > 0) {
+            if (pattern.indexOf('\\') >= 0) {
                 // no escape allowed on windows.
                 return;
             }
diff --git a/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java
index 945b6198..193b787c 100644
--- a/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImplTest.java
@@ -41,7 +41,7 @@ public class CopyFileFromContainerCmdImplTest extends AbstractDockerClientTest {
         // TODO extract this into a shared method
         CreateContainerResponse container = dockerClient.createContainerCmd("busybox")
                 .withName("docker-java-itest-copyFromContainer")
-                .withCmd("touch", "/test")
+                .withCmd("touch", "/copyFromContainer")
                 .exec();
 
         LOG.info("Created container: {}", container);
@@ -49,16 +49,22 @@ public class CopyFileFromContainerCmdImplTest extends AbstractDockerClientTest {
 
         dockerClient.startContainerCmd(container.getId()).exec();
 
-        InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/test").exec();
-        assertTrue(response.available() > 0, "The file was not copied from the container.");
+        InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/copyFromContainer").exec();
+        boolean bytesAvailable = response.available() > 0;
+        assertTrue(bytesAvailable, "The file was not copied from the container.");
+
+        // read the stream fully. Otherwise, the underlying stream will not be closed.
+        String responseAsString = asString(response);
+        assertNotNull(responseAsString);
+        assertTrue(responseAsString.length() > 0);
     }
     
     @Test
     public void copyFromNonExistingContainer() throws Exception {
-    	try {
-    		dockerClient.copyFileFromContainerCmd("non-existing", "/test").exec();
-    		fail("expected NotFoundException");
-		} catch (NotFoundException e) {
-		}
+        try {
+            dockerClient.copyFileFromContainerCmd("non-existing", "/test").exec();
+            fail("expected NotFoundException");
+        } catch (NotFoundException ignored) {
+        }
     }
 }
diff --git a/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java
index 6935227b..941657a1 100644
--- a/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/command/EventsCmdImplTest.java
@@ -19,6 +19,7 @@ import java.lang.reflect.Method;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 @Test(groups = "integration")
 public class EventsCmdImplTest extends AbstractDockerClientTest {
@@ -59,7 +60,7 @@ public class EventsCmdImplTest extends AbstractDockerClientTest {
         String endTime = getEpochTime();
 
         CountDownLatch countDownLatch = new CountDownLatch(expectedEvents);
-        EventCallback eventCallback = new EventCallbackTest(countDownLatch);
+        EventCallbackTest eventCallback = new EventCallbackTest(countDownLatch);
 
         EventsCmd eventsCmd = dockerClient.eventsCmd(eventCallback).withSince(startTime).withUntil(endTime);
         ExecutorService executorService = eventsCmd.exec();
@@ -67,8 +68,8 @@ public class EventsCmdImplTest extends AbstractDockerClientTest {
         boolean zeroCount = countDownLatch.await(5, TimeUnit.SECONDS);
 
         executorService.shutdown();
-        
-        
+        eventCallback.close();
+
         assertTrue(zeroCount, "Expected 4 events, [create, start, die, stop]");
     }
 
@@ -78,7 +79,7 @@ public class EventsCmdImplTest extends AbstractDockerClientTest {
         TimeUnit.SECONDS.sleep(1);
 
         CountDownLatch countDownLatch = new CountDownLatch(KNOWN_NUM_EVENTS);
-        EventCallback eventCallback = new EventCallbackTest(countDownLatch);
+        EventCallbackTest eventCallback = new EventCallbackTest(countDownLatch);
 
         EventsCmd eventsCmd = dockerClient.eventsCmd(eventCallback).withSince(getEpochTime());
         ExecutorService executorService = eventsCmd.exec();
@@ -87,6 +88,7 @@ public class EventsCmdImplTest extends AbstractDockerClientTest {
 
         boolean zeroCount = countDownLatch.await(5, TimeUnit.SECONDS);
         executorService.shutdown();
+        eventCallback.close();
         assertTrue(zeroCount, "Expected 4 events, [create, start, die, stop]");
     }
 
@@ -105,11 +107,16 @@ public class EventsCmdImplTest extends AbstractDockerClientTest {
 
     private class EventCallbackTest implements EventCallback {
         private final CountDownLatch countDownLatch;
+        private final AtomicBoolean isReceiving = new AtomicBoolean(true);
 
         public EventCallbackTest(CountDownLatch countDownLatch) {
             this.countDownLatch = countDownLatch;
         }
 
+        public void close() {
+            isReceiving.set(false);
+        }
+
         @Override
         public void onEvent(Event event) {
             LOG.info("Received event #{}: {}", countDownLatch.getCount(), event);
@@ -125,5 +132,10 @@ public class EventsCmdImplTest extends AbstractDockerClientTest {
         public void onCompletion(int numEvents) {
             LOG.info("Number of events received: {}", numEvents);
         }
+
+        @Override
+        public boolean isReceiving() {
+            return isReceiving.get();
+        }
     }
 }
diff --git a/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java
index a8c3fe8a..497c44c1 100644
--- a/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/command/ExecStartCmdImplTest.java
@@ -42,19 +42,26 @@ public class ExecStartCmdImplTest extends AbstractDockerClientTest {
         String containerName = "generated_" + new SecureRandom().nextInt();
 
         CreateContainerResponse container = dockerClient
-                .createContainerCmd("busybox").withCmd("top")
+                .createContainerCmd("busybox")
+                .withCmd("top")
                 .withName(containerName).exec();
-
         LOG.info("Created container {}", container.toString());
-
         assertThat(container.getId(), not(isEmptyString()));
 
         dockerClient.startContainerCmd(container.getId()).exec();
 
-        ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId()).withAttachStdout(true).withCmd("touch","file.log").exec();
+        ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(container.getId())
+            .withAttachStdout(true)
+            .withCmd("touch", "/execStartTest.log").exec();
         dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec();
 
-        InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/file.log").exec();
-        assertTrue(response.available() > 0, "The file was not copied from the container.");
+        InputStream response = dockerClient.copyFileFromContainerCmd(container.getId(), "/execStartTest.log").exec();
+        boolean bytesAvailable = response.available() > 0;
+        assertTrue(bytesAvailable, "The file was not copied from the container.");
+
+        // read the stream fully. Otherwise, the underlying stream will not be closed.
+        String responseAsString = asString(response);
+        assertNotNull(responseAsString);
+        assertTrue(responseAsString.length() > 0);
     }
 }
diff --git a/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java
index 37214418..a0a272f2 100644
--- a/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/command/InfoCmdImplTest.java
@@ -45,6 +45,7 @@ public class InfoCmdImplTest extends AbstractDockerClientTest {
 	public void info() throws DockerException {
         // Make sure that there is at least one container for the assertion
         // TODO extract this into a shared method
+    if (dockerClient.listContainersCmd().withShowAll(true).exec().size() == 0) {
         CreateContainerResponse container = dockerClient.createContainerCmd("busybox")
                 .withName("docker-java-itest-info")
                 .withCmd("touch", "/test")
@@ -54,8 +55,9 @@ public class InfoCmdImplTest extends AbstractDockerClientTest {
         assertThat(container.getId(), not(isEmptyOrNullString()));
 
         dockerClient.startContainerCmd(container.getId()).exec();
+    }
 
-        Info dockerInfo = dockerClient.infoCmd().exec();
+		Info dockerInfo = dockerClient.infoCmd().exec();
 		LOG.info(dockerInfo.toString());
 
 		assertTrue(dockerInfo.toString().contains("containers"));
@@ -68,6 +70,4 @@ public class InfoCmdImplTest extends AbstractDockerClientTest {
 		assertTrue(dockerInfo.getNGoroutines() > 0);
 		assertTrue(dockerInfo.isMemoryLimit());
 	}
-
-
 }
diff --git a/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java
index 394e86bd..43291f07 100644
--- a/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/command/PullImageCmdImplTest.java
@@ -109,12 +109,14 @@ public class PullImageCmdImplTest extends AbstractDockerClientTest {
 	public void testPullNonExistingImage() throws DockerException, IOException {
 		
 		// does not throw an exception
-		dockerClient.pullImageCmd("nonexisting/foo").exec();
+		InputStream is = dockerClient.pullImageCmd("nonexisting/foo").exec();
+		// stream needs to be fully read in order to close the underlying connection
+		this.asString(is);
 		
 		try {
 			dockerClient.pullImageCmd("non-existing/foo").exec();
 			fail("expected InternalServerErrorException");
-		} catch (InternalServerErrorException e) {
+		} catch (InternalServerErrorException ignored) {
 		}
 		
 	}
diff --git a/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java
index 2e2c9134..f409aebf 100644
--- a/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java
+++ b/src/test/java/com/github/dockerjava/core/command/PushImageCmdImplTest.java
@@ -71,6 +71,5 @@ public class PushImageCmdImplTest extends AbstractDockerClientTest {
 		assertThat(asString(dockerClient.pushImageCmd(username + "/xxx").exec()), containsString("error"));
 	}
 
-
 }