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");
