Updated Branches:
  refs/heads/1.6.x 7dc52f52e -> e86462d49

Properly set the request method in HTTPS connections


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/e86462d4
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/e86462d4
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/e86462d4

Branch: refs/heads/1.6.x
Commit: e86462d499a2a98f0a07592b6181eb96bc22181c
Parents: 7dc52f5
Author: Ignasi Barrera <[email protected]>
Authored: Thu Dec 12 16:25:16 2013 +0100
Committer: Ignasi Barrera <[email protected]>
Committed: Thu Dec 12 21:58:49 2013 +0100

----------------------------------------------------------------------
 .../JavaUrlHttpCommandExecutorService.java      | 65 ++++++++++++++++----
 1 file changed, 52 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/e86462d4/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
 
b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
index fac7c55..5be0023 100644
--- 
a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
+++ 
b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
@@ -79,7 +79,6 @@ public class JavaUrlHttpCommandExecutorService extends 
BaseHttpCommandExecutorSe
    private final Supplier<SSLContext> untrustedSSLContextProvider;
    private final Function<URI, Proxy> proxyForURI;
    private final HostnameVerifier verifier;
-   private final Field methodField;
    @Inject(optional = true)
    Supplier<SSLContext> sslContextSupplier;
 
@@ -96,8 +95,6 @@ public class JavaUrlHttpCommandExecutorService extends 
BaseHttpCommandExecutorSe
       this.untrustedSSLContextProvider = 
checkNotNull(untrustedSSLContextProvider, "untrustedSSLContextProvider");
       this.verifier = checkNotNull(verifier, "verifier");
       this.proxyForURI = checkNotNull(proxyForURI, "proxyForURI");
-      this.methodField = HttpURLConnection.class.getDeclaredField("method");
-      this.methodField.setAccessible(true);
    }
 
    @Override
@@ -175,16 +172,8 @@ public class JavaUrlHttpCommandExecutorService extends 
BaseHttpCommandExecutorSe
       // ex. Caused by: java.io.IOException: HTTPS hostname wrong: should be
       // <adriancole.s3int0.s3-external-3.amazonaws.com>
       connection.setInstanceFollowRedirects(false);
-      try {
-         connection.setRequestMethod(request.getMethod());
-      } catch (ProtocolException e) {
-         try {
-            methodField.set(connection, request.getMethod());
-         } catch (IllegalAccessException e1) {
-            logger.error(e, "could not set request method: ", 
request.getMethod());
-            propagate(e1);
-         }
-      }
+
+      setRequestMethodBypassingJREMethodLimitation(connection, 
request.getMethod());
 
       for (Map.Entry<String, String> entry : request.getHeaders().entries()) {
          connection.setRequestProperty(entry.getKey(), entry.getValue());
@@ -228,6 +217,56 @@ public class JavaUrlHttpCommandExecutorService extends 
BaseHttpCommandExecutorSe
       return connection;
    }
 
+   /**
+    * Workaround for a bug in 
<code>HttpURLConnection.setRequestMethod(String)</code>
+    * The implementation of Sun Microsystems is throwing a 
<code>ProtocolException</code>
+    * when the method is other than the HTTP/1.1 default methods. So
+    * to use PATCH and others, we must apply this workaround.
+    *
+    * See issue http://java.net/jira/browse/JERSEY-639
+    */
+   private void setRequestMethodBypassingJREMethodLimitation(final 
HttpURLConnection httpURLConnection, final String method) {
+      try {
+         httpURLConnection.setRequestMethod(method);
+         // If the JRE does not support the given method, set it using 
reflection
+      } catch (final ProtocolException pe) {
+         Class<?> connectionClass = httpURLConnection.getClass();
+         Field delegateField = null;
+         try {
+            // SSL connections may have the HttpURLConnection wrapped inside
+            delegateField = connectionClass.getDeclaredField("delegate");
+            delegateField.setAccessible(true);
+            HttpURLConnection delegateConnection = (HttpURLConnection) 
delegateField.get(httpURLConnection);
+            setRequestMethodBypassingJREMethodLimitation(delegateConnection, 
method);
+         } catch (NoSuchFieldException e) {
+            // Ignore for now, keep going
+         } catch (IllegalArgumentException e) {
+            logger.error(e, "could not set request method: ", method);
+            propagate(e);
+         } catch (IllegalAccessException e) {
+            logger.error(e, "could not set request method: ", method);
+            propagate(e);
+         }
+         try {
+            Field methodField = null;
+            while (connectionClass != null) {
+               try {
+                  methodField = connectionClass.getDeclaredField("method");
+               } catch (NoSuchFieldException e) {
+                  connectionClass = connectionClass.getSuperclass();
+                  continue;
+               }
+               methodField.setAccessible(true);
+               methodField.set(httpURLConnection, method);
+               break;
+            }
+         } catch (final Exception e) {
+            logger.error(e, "could not set request method: ", method);
+            propagate(e);
+         }
+      }
+   }
+
    protected void writeNothing(HttpURLConnection connection) {
       if 
(!HttpRequest.NON_PAYLOAD_METHODS.contains(connection.getRequestMethod())) {
          connection.setRequestProperty(CONTENT_LENGTH, "0");

Reply via email to