You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ev...@apache.org on 2013/12/12 19:30:31 UTC

git commit: Properly set the request method in HTTPS connections

Updated Branches:
  refs/heads/master 828d8790c -> cec0981bb


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/cec0981b
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/cec0981b
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/cec0981b

Branch: refs/heads/master
Commit: cec0981bb925d6ccaf048727ae064a3827b3d1c3
Parents: 828d879
Author: Ignasi Barrera <na...@apache.org>
Authored: Thu Dec 12 16:25:16 2013 +0100
Committer: Everett Toews <ev...@rackspace.com>
Committed: Thu Dec 12 12:30:06 2013 -0600

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


http://git-wip-us.apache.org/repos/asf/jclouds/blob/cec0981b/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 9a8cb90..3e2b5db 100644
--- a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
+++ b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java
@@ -78,7 +78,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;
 
@@ -95,8 +94,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
@@ -174,16 +171,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());
@@ -227,6 +216,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");