hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Dmitry Potapov (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (HTTPCLIENT-1439) Infinite timeout on entity send
Date Tue, 26 Nov 2013 21:51:35 GMT

     [ https://issues.apache.org/jira/browse/HTTPCLIENT-1439?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Dmitry Potapov updated HTTPCLIENT-1439:
---------------------------------------

    Description: 
Steps to reproduce:
1. Create HttpClient with RequestConfig.setSocketTimeout(1000)
2. Create ByteArrayEntity with 10 MB entity (entity size must be greater that default socket
send/receive buffer size)
3. Create ServerSocket and bind it to any port
4. Try to send HttpPost to this port with aforementioned entity

Expected result:
SocketTimeoutException is raised after 1 second since request start

Actual result:
Request send hangs

Root cause:
According to javadocs Socket.setSoTimeout() affects only .read() operations and nothing said
about write operations. While client tries to send data to the remote port it receives TCP
ZeroWindow messages in return, so formally connection is still alive and won't be closed by
system.

Possible solution:
1. Start daemon thread somewhere in PoolingHttpClientManager which will perform monitoring
of all connections in this pool (say, once per 100 ms)
2. Each time new connection created, register it in monitoring thread object
3. Each time SessionInputBufferImpl enters .write() function, set connection state to WRITE
(and set it to IDLE in finally section)
4. Monitoring thread will iterate over all known connections and if connection state is WRITE
then compare state timestamp and current time. If difference is more than timeout then close
socket

I've prepared small test which demonstrates the problem. HttpAsyncClient is not affected by
this issue (because reactor threads already works as monitoring threads).


import java.net.ServerSocket;

import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.SocketConfig;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.entity.NByteArrayEntity;
public class Main {
    public static void main(final String[] args) throws Exception {
        ServerSocket socket = new ServerSocket(0);
        System.out.println("Listening port " + socket.getLocalPort());
        CloseableHttpAsyncClient client = HttpAsyncClients.custom()
            .setDefaultRequestConfig(RequestConfig.custom()
                .setSocketTimeout(1000)
                .build())
            .build();
        client.start();
        HttpPost post = new HttpPost("http://localhost:" + socket.getLocalPort());
        post.setEntity(new NByteArrayEntity(new byte[10000000]));
        System.out.println("Sending request");
        client.execute(post, new FutureCallback<HttpResponse>() {
            public void cancelled() {
            }
            public void completed(final HttpResponse response) {
            }
            public void failed(final Exception e) {
                System.out.println("Request failed: " + e);
            }
        });
        Thread.sleep(2000);
        CloseableHttpClient client2 = HttpClients.custom()
            .setDefaultRequestConfig(RequestConfig.custom()
                .setSocketTimeout(1000)
                .build())
            .build();
        post.setEntity(new ByteArrayEntity(new byte[10000000]));
        System.out.println("\nSending second request");
        try {
            client2.execute(post);
        } catch (Exception e) {
            System.out.println("Exception caught on second request");
        }
        System.out.println("Second request executed");
    }
}


I'm not sure that solution suggested is acceptable.
Also I'm not sure that I'll have enough time to provide this solution by myself in this year.

  was:
Steps to reproduce:
1. Create HttpClient with RequestConfig.setSocketTimeout(1000)
2. Create ByteArrayEntity with 10 MB entity (entity size must be greater that default socket
send/receive buffer size)
3. Create ServerSocket and bind it to any port
4. Try to send HttpPost to this port with aforementioned entity

Expected result:
SocketTimeoutException is raised after 1 second since request start

Actual result:
Request send hangs

Root cause:
According to javadocs Socket.setSoTimeout() affects only .read() operations and nothing said
about write operations. While client tries to send data to the remote port it receives TCP
ZeroWindow messages in return, so formally connection is still alive and won't be closed by
system.

Possible solution:
1. Start daemon thread somewhere in PoolingHttpClientManager which will perform monitoring
of all connections in this pool (say, once per 100 ms)
2. Each time new connection created, register it in monitoring thread object
3. Each time SessionInputBufferImpl enters .write() function, set connection state to ##WRITE##
(and set it to IDLE in finally section)
4. Monitoring thread will iterate over all known connections and if connection state is ##WRITE##
then compare state timestamp and current time. If difference is more than timeout then close
socket

I've prepared small test which demonstrates the problem. HttpAsyncClient is not affected by
this issue (because reactor threads already works as monitoring threads).

%%
import java.net.ServerSocket;

import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.SocketConfig;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.entity.NByteArrayEntity;
public class Main {
    public static void main(final String[] args) throws Exception {
        ServerSocket socket = new ServerSocket(0);
        System.out.println("Listening port " + socket.getLocalPort());
        CloseableHttpAsyncClient client = HttpAsyncClients.custom()
            .setDefaultRequestConfig(RequestConfig.custom()
                .setSocketTimeout(1000)
                .build())
            .build();
        client.start();
        HttpPost post = new HttpPost("http://localhost:" + socket.getLocalPort());
        post.setEntity(new NByteArrayEntity(new byte[10000000]));
        System.out.println("Sending request");
        client.execute(post, new FutureCallback<HttpResponse>() {
            public void cancelled() {
            }
            public void completed(final HttpResponse response) {
            }
            public void failed(final Exception e) {
                System.out.println("Request failed: " + e);
            }
        });
        Thread.sleep(2000);
        CloseableHttpClient client2 = HttpClients.custom()
            .setDefaultRequestConfig(RequestConfig.custom()
                .setSocketTimeout(1000)
                .build())
            .build();
        post.setEntity(new ByteArrayEntity(new byte[10000000]));
        System.out.println("\nSending second request");
        try {
            client2.execute(post);
        } catch (Exception e) {
            System.out.println("Exception caught on second request");
        }
        System.out.println("Second request executed");
    }
}
%%

I'm not sure that solution suggested is acceptable.
Also I'm not sure that I'll have enough time to provide this solution by myself in this year.


> Infinite timeout on entity send
> -------------------------------
>
>                 Key: HTTPCLIENT-1439
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-1439
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>          Components: HttpClient
>    Affects Versions: 4.3.1
>            Reporter: Dmitry Potapov
>            Priority: Minor
>
> Steps to reproduce:
> 1. Create HttpClient with RequestConfig.setSocketTimeout(1000)
> 2. Create ByteArrayEntity with 10 MB entity (entity size must be greater that default
socket send/receive buffer size)
> 3. Create ServerSocket and bind it to any port
> 4. Try to send HttpPost to this port with aforementioned entity
> Expected result:
> SocketTimeoutException is raised after 1 second since request start
> Actual result:
> Request send hangs
> Root cause:
> According to javadocs Socket.setSoTimeout() affects only .read() operations and nothing
said about write operations. While client tries to send data to the remote port it receives
TCP ZeroWindow messages in return, so formally connection is still alive and won't be closed
by system.
> Possible solution:
> 1. Start daemon thread somewhere in PoolingHttpClientManager which will perform monitoring
of all connections in this pool (say, once per 100 ms)
> 2. Each time new connection created, register it in monitoring thread object
> 3. Each time SessionInputBufferImpl enters .write() function, set connection state to
WRITE (and set it to IDLE in finally section)
> 4. Monitoring thread will iterate over all known connections and if connection state
is WRITE then compare state timestamp and current time. If difference is more than timeout
then close socket
> I've prepared small test which demonstrates the problem. HttpAsyncClient is not affected
by this issue (because reactor threads already works as monitoring threads).
> import java.net.ServerSocket;
> import org.apache.http.concurrent.FutureCallback;
> import org.apache.http.config.SocketConfig;
> import org.apache.http.client.config.RequestConfig;
> import org.apache.http.client.methods.HttpPost;
> import org.apache.http.entity.ByteArrayEntity;
> import org.apache.http.impl.client.CloseableHttpClient;
> import org.apache.http.impl.client.HttpClients;
> import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
> import org.apache.http.impl.nio.client.HttpAsyncClients;
> import org.apache.http.nio.entity.NByteArrayEntity;
> public class Main {
>     public static void main(final String[] args) throws Exception {
>         ServerSocket socket = new ServerSocket(0);
>         System.out.println("Listening port " + socket.getLocalPort());
>         CloseableHttpAsyncClient client = HttpAsyncClients.custom()
>             .setDefaultRequestConfig(RequestConfig.custom()
>                 .setSocketTimeout(1000)
>                 .build())
>             .build();
>         client.start();
>         HttpPost post = new HttpPost("http://localhost:" + socket.getLocalPort());
>         post.setEntity(new NByteArrayEntity(new byte[10000000]));
>         System.out.println("Sending request");
>         client.execute(post, new FutureCallback<HttpResponse>() {
>             public void cancelled() {
>             }
>             public void completed(final HttpResponse response) {
>             }
>             public void failed(final Exception e) {
>                 System.out.println("Request failed: " + e);
>             }
>         });
>         Thread.sleep(2000);
>         CloseableHttpClient client2 = HttpClients.custom()
>             .setDefaultRequestConfig(RequestConfig.custom()
>                 .setSocketTimeout(1000)
>                 .build())
>             .build();
>         post.setEntity(new ByteArrayEntity(new byte[10000000]));
>         System.out.println("\nSending second request");
>         try {
>             client2.execute(post);
>         } catch (Exception e) {
>             System.out.println("Exception caught on second request");
>         }
>         System.out.println("Second request executed");
>     }
> }
> I'm not sure that solution suggested is acceptable.
> Also I'm not sure that I'll have enough time to provide this solution by myself in this
year.



--
This message was sent by Atlassian JIRA
(v6.1#6144)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org


Mime
View raw message