From e9c8d6471fea2e1f3705d09de93bc97ec79302a9 Mon Sep 17 00:00:00 2001 From: Ryan Mentley Date: Tue, 6 Aug 2013 22:14:36 -0700 Subject: [PATCH] Thread safety This is to improve thread safety for static methods that may be called from multiple threads. This change does not affect the thread safety of individual HttpRequest instances. Use ThreadLocal for trustedFactory, as the documentation for the classes used makes no thread- safety guarantees. Make TRUSTED_VERIFIER final and initialize lazily using the lazy initialization holder class idiom used in Effective Java item 71, as the implementation used is thread-safe. Make connectionFactory volatile. This requires implementers of the ConnectionFactory interface to ensure that their implementation is thread-safe. This also changes the static members used that were not final to use the more conventional camelCase naming rather than ALL_CAPS. --- .../github/kevinsawicki/http/HttpRequest.java | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/src/main/java/com/github/kevinsawicki/http/HttpRequest.java b/lib/src/main/java/com/github/kevinsawicki/http/HttpRequest.java index a9957edd..3e1c9b1a 100644 --- a/lib/src/main/java/com/github/kevinsawicki/http/HttpRequest.java +++ b/lib/src/main/java/com/github/kevinsawicki/http/HttpRequest.java @@ -253,9 +253,16 @@ public class HttpRequest { private static final String[] EMPTY_STRINGS = new String[0]; - private static SSLSocketFactory TRUSTED_FACTORY; + private static final ThreadLocal trustedFactory = new ThreadLocal(); - private static HostnameVerifier TRUSTED_VERIFIER; + private static class VerifierHolder { + private static final HostnameVerifier TRUSTED_VERIFIER = new HostnameVerifier() { + + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + } private static String getValidCharset(final String charset) { if (charset != null && charset.length() > 0) @@ -266,7 +273,7 @@ private static String getValidCharset(final String charset) { private static SSLSocketFactory getTrustedFactory() throws HttpRequestException { - if (TRUSTED_FACTORY == null) { + if (trustedFactory.get() == null) { final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { @@ -284,7 +291,7 @@ public void checkServerTrusted(X509Certificate[] chain, String authType) { try { SSLContext context = SSLContext.getInstance("TLS"); context.init(null, trustAllCerts, new SecureRandom()); - TRUSTED_FACTORY = context.getSocketFactory(); + trustedFactory.set(context.getSocketFactory()); } catch (GeneralSecurityException e) { IOException ioException = new IOException( "Security exception configuring SSL context"); @@ -293,19 +300,11 @@ public void checkServerTrusted(X509Certificate[] chain, String authType) { } } - return TRUSTED_FACTORY; + return trustedFactory.get(); } private static HostnameVerifier getTrustedVerifier() { - if (TRUSTED_VERIFIER == null) - TRUSTED_VERIFIER = new HostnameVerifier() { - - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - return TRUSTED_VERIFIER; + return VerifierHolder.TRUSTED_VERIFIER; } private static StringBuilder addPathSeparator(final String baseUrl, @@ -366,16 +365,16 @@ public HttpURLConnection create(URL url, Proxy proxy) throws IOException { }; } - private static ConnectionFactory CONNECTION_FACTORY = ConnectionFactory.DEFAULT; + private static volatile ConnectionFactory connectionFactory = ConnectionFactory.DEFAULT; /** * Specify the {@link ConnectionFactory} used to create new requests. */ public static void setConnectionFactory(final ConnectionFactory connectionFactory) { if (connectionFactory == null) - CONNECTION_FACTORY = ConnectionFactory.DEFAULT; + HttpRequest.connectionFactory = ConnectionFactory.DEFAULT; else - CONNECTION_FACTORY = connectionFactory; + HttpRequest.connectionFactory = connectionFactory; } /** @@ -1419,9 +1418,9 @@ private HttpURLConnection createConnection() { try { final HttpURLConnection connection; if (httpProxyHost != null) - connection = CONNECTION_FACTORY.create(url, createProxy()); + connection = connectionFactory.create(url, createProxy()); else - connection = CONNECTION_FACTORY.create(url); + connection = connectionFactory.create(url); connection.setRequestMethod(requestMethod); return connection; } catch (IOException e) {