-1

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);
        }
    }
lanmaster
  • 330
  • 2
  • 16
  • Do you consume message content in case of a response with non 2xx status? – ok2c Aug 24 '15 at 13:34
  • No, this situation occure only if server set answer status code 400. I was test with 200, 401, 402 codes and there is normal working. Problem is in 400 error code only. And i must add some info: problem with 400 code exists only with non-empty entity. If server not set entity or set empty entity then it work normal. – lanmaster Aug 25 '15 at 06:11
  • Do you consume content of the response message or not? – ok2c Aug 25 '15 at 10:41
  • Yes, i consume content of the response message with code 400 on client side. The entity received correctly on client side. The problem was only in exceptions on server side. Code for generate server answer is on block "URL Hander code" in my initial post. – lanmaster Aug 26 '15 at 06:40
  • Are you sure? There is no evidence of that in your sample code, just 'Some next operations with response' comment. Connection reset on the client side generally occurs when the client deems the underlying connection unsafe for re-use, which in most common cases happens if the response message still has unconsumed content – ok2c Aug 26 '15 at 07:56
  • I consume with this code on client: added code to initial post. – lanmaster Aug 27 '15 at 05:31

2 Answers2

0

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.

lanmaster
  • 330
  • 2
  • 16
0

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.

ok2c
  • 26,450
  • 5
  • 63
  • 71