0

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.

Ravi Dasari
  • 453
  • 1
  • 4
  • 10

0 Answers0