I am trying to write a proxy that downloads the file from a service and streams the responses back to the client. And I am getting this Exception at future.get()
call. I am receiving the response buffer back in the consumer as I see it in logs but I think I am doing something wrong in the way I wrote the consumer.
Exception
Caused by: java.util.concurrent.ExecutionException: java.nio.BufferUnderflowException
at org.apache.http.concurrent.BasicFuture.getResult(BasicFuture.java:71)
at org.apache.http.concurrent.BasicFuture.get(BasicFuture.java:84)
at org.apache.http.impl.nio.client.FutureWrapper.get(FutureWrapper.java:70)
at com.test.clients.http.HttpRequestClient.doHttpStreamRequest(HttpRequestClient.java:439)
Source code: package com.test.clients.http;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.nio.CharBuffer;
import java.util.concurrent.Future;
import javax.servlet.http.HttpServletResponse;
public class HttpRequestClient {
private CloseableHttpAsyncClient createAsyncClient()
throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(15000)
.setConnectTimeout(this.connectionTimeout)
.setSocketTimeout(this.connectionTimeout).build();
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustAllStrategy);
return HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setSSLContext(builder.build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setRedirectStrategy(new LaxRedirectStrategy())
.build();
}
private HttpHost getHost() {
return new HttpHost(serverUrl.getHost(), serverUrl.getPort(), serverUrl.getProtocol());
}
private URI getURI(String path, Map<String, String> params) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setPath(path);
for (Map.Entry<String, String> oneParam : params.entrySet()) {
uriBuilder.setParameter(oneParam.getKey(), oneParam.getValue());
}
return uriBuilder.build();
}
public void doHttpStreamRequest(HttpRequestBase request, HttpServletResponse response, Map<String, String> headers, String bodyText) throws Exception {
CloseableHttpAsyncClient client = null;
try {
HttpHost httpHost = getHost();
String requestUrl = request.getRequestLine().getMethod() + ":" +
httpHost.getSchemeName() + "://" + httpHost.getHostName() + ":" + httpHost.getPort() + "/" +
request.getRequestLine().getUri();
client = createAsyncClient();
try {
client.start();
URI uri = new URI(httpHost.getSchemeName(), "hostname", "some/download/url", null, null);
final HttpPost httpPost = new HttpPost(uri);
HttpAsyncRequestProducer producer = HttpAsyncMethods.create(httpPost);
Future<Boolean> future = client.execute(producer, new CustomStreamResponseConsumer(response), null);
Boolean result = future.get();
if (result != null && result.booleanValue()) {
System.out.println("Request successfully executed");
} else {
System.out.println("Request failed");
}
System.out.println("Done processing streaming request");
} finally {
client.close();
}
} catch (IOException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) {
throw new Exception(String.format("Failed to run %s, error: %s", request.getRequestLine().getMethod(), e.getMessage()), e);
} finally {
if (request != null) {
request.releaseConnection();
}
if (client != null) {
try {
client.close();
} catch (IOException e) {
logger.error("Failed closing connection: " + e.getMessage(), e);
}
}
}
}
static class CustomStreamResponseConsumer extends AsyncCharConsumer<Boolean> {
private HttpServletResponse response;
CustomStreamResponseConsumer(HttpServletResponse response) {
super();
this.response = response;
}
@Override
protected void onResponseReceived(final HttpResponse response) {
this.response.setStatus(HttpStatus.SC_OK);
}
@Override
protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
while (buf.hasRemaining()) {
System.out.println("Buffer output: " + buf.get());
this.response.getOutputStream().write(buf.get());
}
this.response.getOutputStream().flush();
}
@Override
protected void releaseResources() {
try {
response.getOutputStream().close();
}
catch(IOException e) {
logger.error("Failed closing output stream: " + e.getMessage(), e);
}
}
@Override
protected Boolean buildResult(final HttpContext context) {
return Boolean.TRUE;
}
}
}
Appreciate any inputs on what is the issue here. I am new to httpasyncclient.