Httpcomponents httpcore and httpclient HTTP_status 400

1.5k Views Asked by At

I am trying to do:

  1. Send request from HttpClient (based on HttpComponents HttpClient 4.5).
  2. Receive that request in HttpServer (based on HttpComponents HttpCore 4.4.1).
  3. HttpServer must answer to HttpClient with different HttpStatus codes and string entities as body.

Problem: If HttpServer make answer with status code 200 (or any others, not checked) then it is worked fine and no exceptions on server side. But if server set answer status code 400, then there is IOException on HttpServer has been occured. Description on russian is "Удаленный хост принудительно разорвал существующее подключение", on english i think it is "Client closed connection". Simple one: on status 200 there is no problem, on 400 it is exception occured on server.

Exception string:

java.io.IOException: Удаленный хост принудительно разорвал существующее подключение at sun.nio.ch.SocketDispatcher.read0(Native Method) ~[na:1.7.0_51] at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43) ~[na:1.7.0_51] at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223) ~[na:1.7.0_51] at sun.nio.ch.IOUtil.read(IOUtil.java:197) ~[na:1.7.0_51] at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:379) ~[na:1.7.0_51] at org.apache.http.nio.reactor.ssl.SSLIOSession.receiveEncryptedData(SSLIOSession.java:449) ~[httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:503) ~[httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:122) ~[httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164) [httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339) [httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317) [httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278) [httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106) [httpcore-nio-4.4.1.jar:4.4.1] at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590) [httpcore-nio-4.4.1.jar:4.4.1] at java.lang.Thread.run(Thread.java:744) [na:1.7.0_51]

HttpServer code:

HttpProcessor httpproc = HttpProcessorBuilder.create()
    .add(new ResponseDate())
    .add(new ResponseServer("HTTP/1.1 WTX Server"))
    .add(new ResponseContent())
    .add(new ResponseConnControl()).build();
UriHttpAsyncRequestHandlerMapper reqistry = new UriHttpAsyncRequestHandlerMapper();
reqistry.register("*", new HttpServerURLHandler());
HttpAsyncService protocolHandler = new HttpServerConnectionsHandler(httpproc, reqistry);
try {
        String keyStoreFile = Config.getString("HTTPServer.keyStoreFile");
        String keyStoreFilePassword = Config.getString("HTTPServer.keyStoreFilePassword");
        FileInputStream fin = new FileInputStream(keyStoreFile);
        KeyStore keystore = KeyStore.getInstance("jks");
        keystore.load(fin, keyStoreFilePassword.toCharArray());
        KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmfactory.init(keystore, keyStoreFilePassword.toCharArray());
        KeyManager[] keymanagers = kmfactory.getKeyManagers();
        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(keymanagers, null, null);
        NHttpConnectionFactory<DefaultNHttpServerConnection> connFactory = new SSLNHttpServerConnectionFactory(sslcontext, null, ConnectionConfig.DEFAULT);

        IOEventDispatch ioEventDispatch = new DefaultHttpServerIODispatch(protocolHandler, connFactory);

        IOReactorConfig config = IOReactorConfig.custom()
                //.setIoThreadCount(10)
                //.setSoTimeout(5000)
                //.setConnectTimeout(4000)
                //.setSoKeepAlive(true)
                //.setSoReuseAddress(true)
                //.setRcvBufSize(65535)
                //.setTcpNoDelay(true)
                .build();

        ListeningIOReactor ioReactor = new DefaultListeningIOReactor(config);
        ioReactor.listen(new InetSocketAddress(socketAddr, socketPort));
        ioReactor.execute(ioEventDispatch);

    } catch (Exception e) {
        MDC.put(ApplicationInit.LOGGERVAR, ApplicationInit.LOGGERCTX.HTTPSERVER.toString());
        logger.error("Error while creating HTTP Server instance.", e);
    }

URL Hander code:

public class HttpServerURLHandler implements HttpAsyncRequestHandler<HttpRequest> {

public static final Logger logger = LoggerFactory.getLogger(HttpServerURLHandler.class);

private BasicHttpResponse httpResponse = null;

public HttpServerURLHandler() {
    super();
}

public HttpAsyncRequestConsumer<HttpRequest> processRequest(final HttpRequest request, final HttpContext context) {
    return new BasicAsyncRequestConsumer();
}

public void handle(final HttpRequest httpRequest, final HttpAsyncExchange httpExchange, final HttpContext httpContext) throws HttpException, IOException {
    String string1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ++++++++++++++++++++++++++++++++++++++++++++++++abcdefghijklmnopqrstuvwxyz";
    string1 +=       "ABCDEFGHIJKLMNOPQRSTUVWXYZ++++++++++++++++++++++++++++++++++++++++++++++++abcdefghijklmnopqrstuvwxyz";

    int httpCode = 400;

    String httpCodeString = EnglishReasonPhraseCatalog.INSTANCE.getReason(httpCode, Locale.ENGLISH);
    BasicHttpResponse httpResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, httpCode, httpCodeString);
    NStringEntity answerEntity = new NStringEntity(stringXML, Consts.UTF_8);
    httpResponse.setEntity(answerEntity);
    httpExchange.submitResponse(new BasicAsyncResponseProducer(httpResponse));
}

}

Client code:

    RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(20000)
            .setConnectionRequestTimeout(20000)
            .setSocketTimeout(20000)
            .build();

    SSLContext sslContext = null;
    try {
        TrustStrategy trustStrategy = new TrustStrategy() {
            public boolean isTrusted(X509Certificate[] arg0, String arg1) {
                return true;
            }
        };
        sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build();
    } catch (Exception e) {
        MDC.put(ApplicationInit.LOGGERVAR, ApplicationInit.LOGGERCTX.HTTPCLIENT.toString());
        logger.error("Error while creating SSL context for making HTTP request", e);
    }

    CloseableHttpClient client = HttpClientBuilder.create()
            .setDefaultRequestConfig(config)
            .setSSLContext(sslContext)
            .setSSLHostnameVerifier(new NoopHostnameVerifier())
            .build();

    String stringURL = "https://serverhost:port/";
    try {
        HttpPost post = new HttpPost(stringURL);
        post.setEntity(httpClientRequest.getEntity());
        CloseableHttpResponse httpResponse = client.execute(post);

        // Consume entity code
        HttpEntity responseEntity = httpResponse.getEntity();
        String stringXMLAnswer = EntityUtils.toString(responseEntity);
        EntityUtils.consume(responseEntity);

        // Some next operations with responseEntity

    } catch (Exception e) {
        MDC.put(ApplicationInit.LOGGERVAR, ApplicationInit.LOGGERCTX.HTTPCLIENT.toString());
        logger.error("Error while make request.", e);
    } finally {
        try {
            // Closing connection
            client.close();
        } catch (Exception e) {
            MDC.put(ApplicationInit.LOGGERVAR, ApplicationInit.LOGGERCTX.HTTPCLIENT.toString());
            logger.error("Error while closing connection after making request", e);
        }
    }
2

There are 2 best solutions below

0
On BEST ANSWER

The connection reset is likely to be caused by HTTPCLIENT-1655. Please try the latest 4.5.x snapshot and see if that fixes the problem.

0
On

I was find org.apache.http.protocol.ResponseConnControl with code

        if (status == HttpStatus.SC_BAD_REQUEST ||
            status == HttpStatus.SC_REQUEST_TIMEOUT ||
            status == HttpStatus.SC_LENGTH_REQUIRED ||
            status == HttpStatus.SC_REQUEST_TOO_LONG ||
            status == HttpStatus.SC_REQUEST_URI_TOO_LONG ||
            status == HttpStatus.SC_SERVICE_UNAVAILABLE ||
            status == HttpStatus.SC_NOT_IMPLEMENTED) {
        response.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
        return;
    }

My problem reproduced by this status codes.