Repository: docker-java/docker-java
Pull request #149 (2015-02-11 23:15:44)

Redirects
Issues #147 


Patch:
diff --git a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
index 7513c7f2..6b87a927 100644
--- a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
+++ b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java
@@ -33,6 +33,7 @@ public class DockerClientConfig implements Serializable {
     private static final String DOCKER_IO_READ_TIMEOUT_PROPERTY = "docker.io.readTimeout";
     // this is really confusing, as there are two ways to spell it
     private static final String DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY = "docker.io.enableLoggingFilter";
+    private static final String DOCKER_IO_FOLLOW_REDIRECTS_FILTER_PROPERTY = "docker.io.followRedirectsFilter";
     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
@@ -53,6 +54,7 @@ public class DockerClientConfig implements Serializable {
         m.put("DOCKER_SERVER_ADDRESS", DOCKER_IO_SERVER_ADDRESS_PROPERTY);
         m.put("DOCKER_READ_TIMEOUT", DOCKER_IO_READ_TIMEOUT_PROPERTY);
         m.put("DOCKER_LOGGING_FILTER_ENABLED", DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY);
+        m.put("DOCKER_FOLLOW_REDIRECTS_FILTER_ENABLED", DOCKER_IO_FOLLOW_REDIRECTS_FILTER_PROPERTY);
         m.put(DOCKER_CERT_PATH_PROPERTY, DOCKER_IO_DOCKER_CERT_PATH_PROPERTY);
         m.put("DOCKER_CFG_PATH", DOCKER_IO_DOCKER_CFG_PATH_PROPERTY);
         ENV_NAME_TO_IO_NAME = Collections.unmodifiableMap(m);
@@ -63,14 +65,15 @@ public class DockerClientConfig implements Serializable {
     private final String version, username, password, email, serverAddress, dockerCfgPath;
     private final Integer readTimeout;
     private final boolean loggingFilterEnabled;
+    private final boolean followRedirectsFilterEnabled;
     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,
-                       int maxTotalConns, int maxPerRouteConns) {
+                       String dockerCfgPath, Integer readTimeout, boolean loggingFilterEnabled, boolean followRedirectsFilterEnabled,
+                       SSLConfig sslConfig, int maxTotalConns, int maxPerRouteConns) {
         this.uri = uri;
         this.version = version;
         this.username = username;
@@ -80,6 +83,7 @@ public class DockerClientConfig implements Serializable {
         this.dockerCfgPath = dockerCfgPath;
         this.readTimeout = readTimeout;
         this.loggingFilterEnabled = loggingFilterEnabled;
+        this.followRedirectsFilterEnabled = followRedirectsFilterEnabled;
         this.sslConfig = sslConfig;
         this.maxTotalConnections = maxTotalConns;
         this.maxPerRouteConnections = maxPerRouteConns;
@@ -182,6 +186,7 @@ public class DockerClientConfig implements Serializable {
                 DOCKER_IO_SERVER_ADDRESS_PROPERTY,
                 DOCKER_IO_READ_TIMEOUT_PROPERTY,
                 DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY,
+                DOCKER_IO_FOLLOW_REDIRECTS_FILTER_PROPERTY,
                 DOCKER_IO_DOCKER_CERT_PATH_PROPERTY,
                 DOCKER_IO_DOCKER_CFG_PATH_PROPERTY,
         }) {
@@ -243,6 +248,10 @@ public class DockerClientConfig implements Serializable {
         return loggingFilterEnabled;
     }
 
+    public boolean followRedirectsFilterEnabled() {
+        return followRedirectsFilterEnabled;
+    }
+
     public SSLConfig getSslConfig() {
       return sslConfig;
     }
@@ -345,6 +354,7 @@ public class DockerClientConfig implements Serializable {
                 ", sslConfig='" + sslConfig + '\'' +
                 ", readTimeout=" + readTimeout +
                 ", loggingFilterEnabled=" + loggingFilterEnabled +
+                ", followRedirectsFilterEnabled=" + followRedirectsFilterEnabled +
                 '}';
     }
 
@@ -352,7 +362,7 @@ public class DockerClientConfig implements Serializable {
         private URI uri;
         private String version, username, password, email, serverAddress, dockerCfgPath;
         private Integer readTimeout, maxTotalConnections, maxPerRouteConnections;
-        private boolean loggingFilterEnabled;
+        private boolean loggingFilterEnabled, followRedirectsFilterEnabled;
         private SSLConfig sslConfig;
 
         /**
@@ -370,6 +380,7 @@ public class DockerClientConfig implements Serializable {
                     .withServerAddress(p.getProperty(DOCKER_IO_SERVER_ADDRESS_PROPERTY))
                     .withReadTimeout(Integer.valueOf(p.getProperty(DOCKER_IO_READ_TIMEOUT_PROPERTY, "0")))
                     .withLoggingFilter(Boolean.valueOf(p.getProperty(DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY, "true")))
+                    .withFollowRedirectsFilter(Boolean.valueOf(p.getProperty(DOCKER_IO_FOLLOW_REDIRECTS_FILTER_PROPERTY, "false")))
                     .withDockerCertPath(p.getProperty(DOCKER_IO_DOCKER_CERT_PATH_PROPERTY))
                     .withDockerCfgPath(p.getProperty(DOCKER_IO_DOCKER_CFG_PATH_PROPERTY))
                     .withMaxPerRouteConnections(Integer.valueOf(p.getProperty(DOCKER_IO_MAX_PER_ROUTE_PROPERTY, "2")))
@@ -428,6 +439,11 @@ public class DockerClientConfig implements Serializable {
             return this;
         }
 
+        public final DockerClientConfigBuilder withFollowRedirectsFilter(boolean followRedirectsFilterEnabled) {
+            this.followRedirectsFilterEnabled = followRedirectsFilterEnabled;
+            return this;
+        }
+
         public final DockerClientConfigBuilder withDockerCertPath(String dockerCertPath) {
             this.sslConfig = new LocalDirectorySSLConfig(dockerCertPath);
             return this;
@@ -455,6 +471,7 @@ public class DockerClientConfig implements Serializable {
                     dockerCfgPath,
                     readTimeout,
                     loggingFilterEnabled,
+                    followRedirectsFilterEnabled,
                     sslConfig,
                     maxTotalConnections,
                     maxPerRouteConnections
diff --git a/src/main/java/com/github/dockerjava/core/util/FollowRedirectsFilter.java b/src/main/java/com/github/dockerjava/core/util/FollowRedirectsFilter.java
new file mode 100644
index 00000000..b4431b1f
--- /dev/null
+++ b/src/main/java/com/github/dockerjava/core/util/FollowRedirectsFilter.java
@@ -0,0 +1,37 @@
+package com.github.dockerjava.core.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.core.Response;
+
+/**
+ * Default implementation of RedirectStrategy honors the restrictions
+ * on automatic redirection of entity enclosing methods such as POST
+ * and PUT imposed by the HTTP specification. 302 Moved Temporarily,
+ * 301 Moved Permanently and 307 Temporary Redirect status codes will
+ * result in an automatic redirect of HEAD and GET methods only.
+ * 
+ * {@link org.apache.http.impl.client.DefaultRedirectStrategy}
+ *
+ * This filter allows arbitrary redirection for other methods.  
+ */
+public class FollowRedirectsFilter implements ClientResponseFilter {
+
+    @Override
+    public void filter(ClientRequestContext requestContext,
+            ClientResponseContext responseContext) throws IOException {
+        if (!responseContext.getStatusInfo().getFamily().equals(Response.Status.Family.REDIRECTION)) {
+            return;
+        }
+
+        Response resp = requestContext.getClient().target(responseContext.getLocation())
+                .request().method(requestContext.getMethod());
+        responseContext.setEntityStream((InputStream) resp.getEntity());
+        responseContext.setStatusInfo(resp.getStatusInfo());
+        responseContext.setStatus(resp.getStatus());
+    }
+}
diff --git a/src/main/java/com/github/dockerjava/core/util/ResponseStatusExceptionFilter.java b/src/main/java/com/github/dockerjava/core/util/ResponseStatusExceptionFilter.java
index 99893a42..7e970856 100644
--- a/src/main/java/com/github/dockerjava/core/util/ResponseStatusExceptionFilter.java
+++ b/src/main/java/com/github/dockerjava/core/util/ResponseStatusExceptionFilter.java
@@ -37,7 +37,6 @@ public class ResponseStatusExceptionFilter implements ClientResponseFilter {
 		case 200:
 		case 201:	
 		case 204:
-		case 301:	
 			return;
 		case 304:
 			throw new NotModifiedException(getBodyAsMessage(responseContext));
diff --git a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
index 4edba9fc..5bff4c66 100644
--- a/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
+++ b/src/main/java/com/github/dockerjava/jaxrs/DockerCmdExecFactoryImpl.java
@@ -6,6 +6,7 @@ import java.io.IOException;
 import java.net.URI;
 
 import com.github.dockerjava.api.command.*;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -28,6 +29,7 @@ import org.glassfish.jersey.client.ClientProperties;
 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
 import com.github.dockerjava.api.DockerClientException;
 import com.github.dockerjava.core.DockerClientConfig;
+import com.github.dockerjava.core.util.FollowRedirectsFilter;
 import com.github.dockerjava.core.util.JsonClientFilter;
 import com.github.dockerjava.core.util.ResponseStatusExceptionFilter;
 import com.github.dockerjava.core.util.SelectiveLoggingFilter;
@@ -46,6 +48,9 @@ public class DockerCmdExecFactoryImpl implements DockerCmdExecFactory {
         clientConfig.connectorProvider(new ApacheConnectorProvider());
         clientConfig.property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
 
+        if (dockerClientConfig.followRedirectsFilterEnabled()) {
+            clientConfig.register(FollowRedirectsFilter.class);
+        }
         clientConfig.register(ResponseStatusExceptionFilter.class);
         clientConfig.register(JsonClientFilter.class);
         clientConfig.register(JacksonJsonProvider.class);


Test patch:
diff --git a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java
index 4611f430..64ab912d 100644
--- a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java
+++ b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java
@@ -16,12 +16,12 @@ 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"), 20, 2);
+        return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flam", 877, false, false, new LocalDirectorySSLConfig("flim"), 20, 2);
     }
 
     @Test
     public void string() throws Exception {
-        assertEquals("DockerClientConfig{uri=http://foo, version='bar', username='baz', password='qux', email='blam', serverAddress='wham', dockerCfgPath='flam', sslConfig='LocalDirectorySSLConfig{dockerCertPath=flim}', readTimeout=877, loggingFilterEnabled=false}",
+        assertEquals("DockerClientConfig{uri=http://foo, version='bar', username='baz', password='qux', email='blam', serverAddress='wham', dockerCfgPath='flam', sslConfig='LocalDirectorySSLConfig{dockerCertPath=flim}', readTimeout=877, loggingFilterEnabled=false, followRedirectsFilterEnabled=false}",
                 EXAMPLE_CONFIG.toString());
     }
 
diff --git a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java
index 1f5604fe..2a961e3b 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, 20, 2);
+        DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null,  0, false, false, null, 20, 2);
         DockerClientImpl dockerClient = DockerClientImpl.getInstance(dockerClientConfig);
 
         // when we get the auth config