From ae8541411f1218ce84d955998a14a24fe63c023e Mon Sep 17 00:00:00 2001 From: Colin Graham Date: Wed, 11 Jul 2018 16:41:16 +0100 Subject: [PATCH 1/2] Reusing http client to avoid building a new one for each request, destroying on ConnectException to avoid thread leak --- .../nl/martijndwars/webpush/PushService.java | 66 ++++++++++++++----- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/src/main/java/nl/martijndwars/webpush/PushService.java b/src/main/java/nl/martijndwars/webpush/PushService.java index f47c4b7..2fb6e30 100644 --- a/src/main/java/nl/martijndwars/webpush/PushService.java +++ b/src/main/java/nl/martijndwars/webpush/PushService.java @@ -1,6 +1,23 @@ package nl.martijndwars.webpush; -import com.google.common.io.BaseEncoding; +import static nl.martijndwars.webpush.Utils.CURVE; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; @@ -16,16 +33,7 @@ import org.jose4j.jwt.JwtClaims; import org.jose4j.lang.JoseException; -import java.io.IOException; -import java.security.*; -import java.security.interfaces.ECPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import static nl.martijndwars.webpush.Utils.CURVE; +import com.google.common.io.BaseEncoding; public class PushService { private static final SecureRandom SECURE_RANDOM = new SecureRandom(); @@ -50,6 +58,11 @@ public class PushService { */ private PrivateKey privateKey; + /** + * Http client + */ + private CloseableHttpAsyncClient closeableHttpAsyncClient; + public PushService() { } @@ -115,10 +128,15 @@ public static Encrypted encrypt(byte[] buffer, PublicKey userPublicKey, byte[] u * @throws InterruptedException */ public HttpResponse send(Notification notification) throws GeneralSecurityException, IOException, JoseException, ExecutionException, InterruptedException { + try { return sendAsync(notification).get(); + } catch (ExecutionException e) { + destroyClient(); + throw e; + } } - /** + /** * Send a notification, but don't wait for the response. * * @param notification @@ -129,14 +147,10 @@ public HttpResponse send(Notification notification) throws GeneralSecurityExcept */ public Future sendAsync(Notification notification) throws GeneralSecurityException, IOException, JoseException { HttpPost httpPost = preparePost(notification); - - final CloseableHttpAsyncClient closeableHttpAsyncClient = HttpAsyncClients.createSystem(); - closeableHttpAsyncClient.start(); - - return closeableHttpAsyncClient.execute(httpPost, new ClosableCallback(closeableHttpAsyncClient)); + return getClient().execute(httpPost, new ClosableCallback(closeableHttpAsyncClient)); } - /** + /** * Prepare a HttpPost for Apache async http client * * @param notification @@ -325,4 +339,20 @@ public PushService setPrivateKey(PrivateKey privateKey) { protected boolean vapidEnabled() { return publicKey != null && privateKey != null; } + + private CloseableHttpAsyncClient getClient() { + if(closeableHttpAsyncClient == null) { + closeableHttpAsyncClient = HttpAsyncClients.createSystem(); + closeableHttpAsyncClient.start(); + } + return closeableHttpAsyncClient; + } + + private void destroyClient() throws IOException { + try { + getClient().close(); + } finally { + closeableHttpAsyncClient = null; + } + } } From 011bdc02ece45cf827b1ca9693fa51c1988afbe7 Mon Sep 17 00:00:00 2001 From: Colin Graham Date: Wed, 11 Jul 2018 16:46:07 +0100 Subject: [PATCH 2/2] Fixing overzealous import reordering --- .../nl/martijndwars/webpush/PushService.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/java/nl/martijndwars/webpush/PushService.java b/src/main/java/nl/martijndwars/webpush/PushService.java index 2fb6e30..d330933 100644 --- a/src/main/java/nl/martijndwars/webpush/PushService.java +++ b/src/main/java/nl/martijndwars/webpush/PushService.java @@ -1,23 +1,6 @@ package nl.martijndwars.webpush; -import static nl.martijndwars.webpush.Utils.CURVE; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.ECPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - +import com.google.common.io.BaseEncoding; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; @@ -33,7 +16,16 @@ import org.jose4j.jwt.JwtClaims; import org.jose4j.lang.JoseException; -import com.google.common.io.BaseEncoding; +import java.io.IOException; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static nl.martijndwars.webpush.Utils.CURVE; public class PushService { private static final SecureRandom SECURE_RANDOM = new SecureRandom();