diff --git a/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpFileExchange.java b/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpFileExchange.java index aa7484664..5dbb0f016 100644 --- a/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpFileExchange.java +++ b/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpFileExchange.java @@ -45,6 +45,7 @@ import org.apache.http.config.SocketConfig; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.ChunkyManagedHttpClientConnectionFactory; @@ -188,7 +189,8 @@ private void performUpload(InputStream in, URL url) throws IOException { ArgumentValidator.checkNotNull(url, "URL url"); - try (CloseableHttpClient httpClient = getHttpClient()) { + try (CloseableHttpClient httpClient = getNonRetryingHttpClient()) { + //non-retrying client as the stream cannot be retried HttpPut httpPut = new HttpPut(url.toExternalForm()); InputStreamEntity reqEntity = new LargeChunkedInputStreamEntity(in); reqEntity.setChunked(true); @@ -242,18 +244,50 @@ protected HttpURLConnection getConnection(URL url) { * @return The HttpClient for this FileExchange. */ protected CloseableHttpClient getHttpClient() { + HttpClientBuilder builder = basicHttpClientBuilder(); + return builder.build(); + } + + /** + * Retrieves the HttpClient with the correct setup. The client will NOT retry failed connections. + * For HTTPS this should be overridden with SSL context. + * @return The HttpClient for this FileExchange. + */ + protected CloseableHttpClient getNonRetryingHttpClient() { + HttpClientBuilder builder = basicHttpClientBuilder(); + builder = nonRetryingHttpClientBuilder(builder); + return builder.build(); + } + + /** + * @return a fresh HttpClientBuilder with the HTTP_CHUNK_SIZE and HTTP_BUFFER_SIZE configured + */ + protected HttpClientBuilder basicHttpClientBuilder(){ + //protected as the subclass HttpsFileExchange uses this method also HttpClientBuilder builder = HttpClients.custom(); PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager( new ChunkyManagedHttpClientConnectionFactory(HTTP_CHUNK_SIZE)); SocketConfig socketConfig = SocketConfig.custom() + .setSoKeepAlive(true) .setSndBufSize(HTTP_BUFFER_SIZE) .setRcvBufSize(HTTP_BUFFER_SIZE) .build(); poolingmgr.setDefaultSocketConfig(socketConfig); builder.setConnectionManager(poolingmgr); - return builder.build(); + return builder; } + /** + * Expands the builder with a non-retrying RetryHandler + * @param builder the http client builder + * @return a http client builder with a non-retrying RetryHandler set + */ + protected HttpClientBuilder nonRetryingHttpClientBuilder(HttpClientBuilder builder){ + //protected as the subclass HttpsFileExchange uses this method also + return builder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)); + + } + @Override public void deleteFile(URL url) throws IOException, URISyntaxException { try (CloseableHttpClient httpClient = getHttpClient()) { diff --git a/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpsFileExchange.java b/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpsFileExchange.java index b548023b6..20cfb3ae4 100644 --- a/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpsFileExchange.java +++ b/bitrepository-core/src/main/java/org/bitrepository/protocol/http/HttpsFileExchange.java @@ -81,9 +81,12 @@ protected HttpURLConnection getConnection(URL url) { } } - @Override - protected CloseableHttpClient getHttpClient() { - HttpClientBuilder builder = HttpClientBuilder.create(); + /** + * Configures a http client builder with SSL + * @param builder the builder to configure + * @return a configured builder + */ + protected HttpClientBuilder sslHttpClientBuilder(HttpClientBuilder builder) { try { Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) @@ -96,17 +99,31 @@ protected CloseableHttpClient getHttpClient() { new ChunkyManagedHttpClientConnectionFactory(HTTP_CHUNK_SIZE), SystemDefaultDnsResolver.INSTANCE); - SocketConfig socketConfig = SocketConfig.custom() - .setSoKeepAlive(true) - .setSndBufSize(HTTP_BUFFER_SIZE) - .setRcvBufSize(HTTP_BUFFER_SIZE).build(); - poolingmgr.setDefaultSocketConfig(socketConfig); - builder.setConnectionManager(poolingmgr); + return builder; } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("Could not make Https Client.", e); } + } + + /** + * @return A SSL-enabled HTTP client + */ + @Override + protected CloseableHttpClient getHttpClient() { + HttpClientBuilder builder = basicHttpClientBuilder(); + builder = sslHttpClientBuilder(builder); + return builder.build(); + } + /** + * @return A SSL-enabled HTTP client that will not retry uploads + */ + @Override + protected CloseableHttpClient getNonRetryingHttpClient() { + HttpClientBuilder builder = basicHttpClientBuilder(); + builder = sslHttpClientBuilder(builder); + builder = nonRetryingHttpClientBuilder(builder); return builder.build(); } }