You are viewing a plain text version of this content. The canonical link for it is here.
Posted to httpclient-users@hc.apache.org by Benjamin Chevillon <bc...@gmail.com> on 2005/06/15 12:08:50 UTC

Abort HttpMethod hangs due to bad proxy config

Hello,

I use HttpClient in my application to download description file. I
work on ensuring that if the application gets closed, everything stop
as fast as possible.

I'm getting problem with this: as many companies network, http request
get out through an http proxy. If I configure correctly the proxy
settings, and if I try to abort a GetMethod, the connection is
immediately stopped, no problem.
Now if I don't configure the proxy settings, the abort method does not
work, and my application hangs until timeout.
As my application will be deployed on many networks on which I cannot
be sure of the correct settings, I cannot accept that the application
hangs until timeout.

For better understanding, here is the unit case I'm using to test it
(source code at the end of this email):
There is two thread:
- The main thread that starts the second one, sleeps for 3 seconds
then aborts the second one.
- The GetMethod thread that execute the GetMethod on a dummy site
(http://test.dyndns.org does not work for me) that do not reply and
timeouts in 10 seconds.

Preliminary for testing:
You must be on a network with a proxy. Configure the proxy settings at
the beginning of the class.

What do the test:
It just gets http://test.dyndns.org

Expected result:
- http://test.dyndns.org does not reply correctly
- so the execute wait for 10 seconds,
- and the main method abort the GetMethod after only 3 seconds
- So the application stops just after the abort and don't wait for 10 seconds.

1st test : with proxy settings.
- uncomment the line "   
client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
- Compile and start the class

Result:
- The application stops correctly in 3 seconds (just after the abort).

2nd test : without proxy settings.
- comment the line "   
client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
- Compile and start the class

Result:
- the abort method is executed in 3 seconds
- BUT the execute method still hangs until the end of the 10 seconds timeout.


Do anybody can produce the same type of acting?
See below my test class and logs.

Thanks in advance

Benjamin Chevillon
France Télécom R&D



---------------------------------------------------------------
File MethodAbortTest.java

import java.io.IOException;
import java.util.Date;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class MethodAbortTest extends Thread {
  public static final String PROXY_HOST = "proxy";
  public static final int PROXY_PORT = 8080;
  // An url that do not reply
  public static final String GETURL = "http://test.dyndns.org/";
  
  HttpClient client;
  

  private GetMethod get;

  public static void main(String[] args) {
    System.setProperty("org.apache.commons.logging.Log",
"org.apache.commons.logging.impl.SimpleLog");
    System.setProperty("org.apache.commons.logging.simplelog.showdatetime",
"true");
    System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire.header",
"debug");
    System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient",
"debug");
    
    MethodAbortTest myTest = new MethodAbortTest();
    myTest.start();
    
    System.out.println("done");
    try {
      Thread.sleep(3000);
    } catch (InterruptedException exc) {
      exc.printStackTrace();
    }

    myTest.cancel();
  }
  
  public void run() {
    HttpClientParams params = new HttpClientParams();
    params.setParameter(HttpMethodParams.RETRY_HANDLER,
        new DefaultHttpMethodRetryHandler(0, true));
    

    client = new HttpClient(params);
    client.getHttpConnectionManager().getParams().setConnectionTimeout(10000);
    // Comment next line to unconfigure proxy settings
    client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
    
    get = new GetMethod(GETURL);

    try {
      System.out.println(new Date() + " execute");
      int statuscode = client.executeMethod(get);
      System.out.println(statuscode);
      System.out.println("execution done");
      // print response to stdout
      System.out.println(get.getResponseBodyAsString());
    } catch (HttpException exc) {
      // TODO Auto-generated catch block
      exc.printStackTrace();
    } catch (IOException exc) {
      // TODO Auto-generated catch block
      System.out.println("IO");
      exc.printStackTrace();
    } finally {
      // be sure the connection is released back to the connection 
      // manager
      System.out.println("End Of HttpGet");
      get.releaseConnection();
    }
  }

  public void cancel() {
    //      this.interrupt();
    System.out.println(new Date() + " canceling");
    get.abort();
    System.out.println("aborted?" + get.isAborted());
  }
}

---------------------------------------------------
With correct proxy setting, the class aborts immediately

done
2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
http.useragent = Jakarta Commons-HttpClient/3.0-rc2
2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.version = HTTP/1.1
2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
http.connection-manager.class = class
org.apache.commons.httpclient.SimpleHttpConnectionManager
2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.cookie-policy = rfc2109
2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.element-charset = US-ASCII
2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.content-charset = ISO-8859-1
2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
http.method.retry-handler =
org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
dd-MM-yyyy HH:mm:ss z]
2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
http.method.retry-handler =
org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java vendor: Sun
Microsystems Inc.
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
name: Windows XP
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
architecture: x86
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system version: 5.1
2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
key/parameter generation; DSA signing; SHA-1, MD5 digests;
SecureRandom; X.509 certificates; JKS keystore; PKIX
CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
factories, SSLv3, TLSv1)
2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
SUN's provider for RSA signatures
2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
Provider (implements DES, Triple DES, AES, Blowfish, PBE,
Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
2005/06/15 10:50:57:207 CEST [DEBUG] DefaultHttpParams - Set parameter
http.connection.timeout = 10000
Wed Jun 15 10:50:57 CEST 2005 execute
2005/06/15 10:50:57:394 CEST [DEBUG] HttpConnection - Open connection
to proxy:8080
2005/06/15 10:50:57:425 CEST [DEBUG] header - >> "GET
http://test.dyndns.org/ HTTP/1.1[\r][\n]"
2005/06/15 10:50:57:441 CEST [DEBUG] HttpMethodBase - Adding Host request header
2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "User-Agent: Jakarta
Commons-HttpClient/3.0-rc2[\r][\n]"
2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Host: test.dyndns.org[\r][\n]"
2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Proxy-Connection:
Keep-Alive[\r][\n]"
2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "[\r][\n]"
Wed Jun 15 10:50:59 CEST 2005 canceling
2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Closing the
connection.
2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Method retry
handler returned false. Automatic recovery will not be attempted
2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
connection back to connection manager.
IO
java.net.SocketException: socket closed
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(SocketInputStream.java:129)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:183)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:201)
	at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:77)
	at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:105)
	at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1110)
	at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1824)
	at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1584)
	at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:995)
	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:393)
End Of HttpGet	at
org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
	at MethodAbortTest.run(MethodAbortTest.java:86)
2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
connection back to connection manager.

aborted?true

---------------------------------------------------
Without proxy, class hangs for 10 seconds

done
2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
http.useragent = Jakarta Commons-HttpClient/3.0-rc2
2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.version = HTTP/1.1
2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
http.connection-manager.class = class
org.apache.commons.httpclient.SimpleHttpConnectionManager
2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.cookie-policy = rfc2109
2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.element-charset = US-ASCII
2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
http.protocol.content-charset = ISO-8859-1
2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
http.method.retry-handler =
org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
dd-MM-yyyy HH:mm:ss z]
2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
http.method.retry-handler =
org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java vendor: Sun
Microsystems Inc.
2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
name: Windows XP
2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
architecture: x86
2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system version: 5.1
2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
key/parameter generation; DSA signing; SHA-1, MD5 digests;
SecureRandom; X.509 certificates; JKS keystore; PKIX
CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
factories, SSLv3, TLSv1)
2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
SUN's provider for RSA signatures
2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
Provider (implements DES, Triple DES, AES, Blowfish, PBE,
Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
2005/06/15 10:54:02:989 CEST [DEBUG] DefaultHttpParams - Set parameter
http.connection.timeout = 10000
Wed Jun 15 10:54:03 CEST 2005 execute
2005/06/15 10:54:03:098 CEST [DEBUG] HttpConnection - Open connection
to test.dyndns.org:80
Wed Jun 15 10:54:05 CEST 2005 canceling
aborted?true
IO
2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Closing the
connection.
2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Method retry
handler returned false. Automatic recovery will not be attempted
2005/06/15 10:54:13:270 CEST [DEBUG] HttpConnection - Releasing
connection back to connection manager.
org.apache.commons.httpclient.ConnectTimeoutException: The host did
not accept the connection within timeout of 10000 ms
	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
	at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)
	at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:704)
	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:382)
	at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
	at MethodAbortTest.run(MethodAbortTest.java:86)
Caused by: java.net.SocketTimeoutException: connect timed out
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
	at java.net.Socket.connect(Socket.java:452)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)End
Of HttpGet

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:324)
	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:139)
	... 7 more

---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: httpclient-user-help@jakarta.apache.org


Re: Abort HttpMethod hangs due to bad proxy config

Posted by Oleg Kalnichevski <ol...@apache.org>.
Benjamin,

Your analysis is correct. Sockets blocked waiting in the connect()
method can indeed be interrupted by calling close() on them. My
assumption was wrong. The trouble is that the changes you are suggesting
cannot be implemented without breaking the existing API. We cannot
change ProtocolSocketFactory interface so late in the release process.
Besides, ability to create unconnected sockets has been introduced in
Java 1.4 and cannot be easily simulated in older versions, whereas
HttpClient must stay Java 1.2 compatible until next major release (4.0
that is). Please file a bug / feature request in Bugzilla and we'll get
this feature incorporated in the next major release of HttpClient. As of
version 4.0 HttpClient will require Java 1.4 or above.

Oleg

On Wed, Jun 15, 2005 at 06:01:59PM +0200, Benjamin Chevillon wrote:
> Thank you for your precise and quick reply.
> Encourage by this precision, I downloaded the source code and traced it.
> Maybe this email should be posted to dev mailing list, except if this
> question has already been fixed.
> 
> Indeed, the client.executeMethod hangs in
> org.apache.commons.httpclient.protocol.ReflectionSocketFactory where
> the socket is opened. It hangs on the line 139 in the trunk CVS
> 138 SOCKETBIND_METHOD.invoke(socket, new Object[] { localaddr});
> 139 SOCKETCONNECT_METHOD.invoke(socket, new Object[] { remoteaddr, new
> Integer(timeout)});
> These 2 lines are similar to 
>         //  socket.bind(localaddr);
>         //  socket.connect(remoteaddr, timeout);
> 
> But I was puzzled when you say that we cannot do much against it,
> because, we can cancel some similar problem on web browser and it
> takes effect immediately.
> 
> Actually, the socket.connect() method can be canceled with
> socket.close(): see the class attached: a socket is opened with a 10
> seconds timeout and a second thread close it only 5 seconds later. It
> works. (sorry for the quick & dirty style of the class)
> 
> It does not work on HttpClient, because the abort() method close only
> the InputStream which is not already created at this moment (since the
> socket hangs on opening).
> There are 2 problems:
> - the socket is open within the same call of its creation (so we don't
> have a pointer to it, to close it).
> - the abort() method has no way to call the close() method deeply.
> 
> The chain of call is here:
> HttpClient.executeMethod() ->...-> HttpConnection.open() ->
> DefaultSocketFactory.createSocket() ->
> ReflectionSocketFactory.createSocket()
> 
> The public class closest to Socket is HttpConnection. A socket is
> created with the open() method. It calls
> ReflectionSocketFactory.createSocket() but inside this method the
> socket.bind(..) and socket.connect(..) methods are not separated and
> hangs. Thus, the HttpConnection.open() method never returns and the
> HttpConnection cannot close() the socket (since it socket variable is
> null).
> 
> To resolve it, there should be 2 calls to ReflectionSocketFactory in
> HttpConnection:
> - One to create the socket (until bind). This method always return
> immediately and this way, we could have a variable that points to the
> Socket instance.
> - A second call to connect the socket.
> If the second call hangs, then we could call HttpConnection.close()
> since the socket variable is not null.
> 
> Finally, there should be a way to for the HttpClient to close the
> HttpConnection which concerns it.
> 
> What do you think about this? Tell me if I am wrong.
> 
> Thanks
> 
> Benjamin
> 
> ------------------------
> import java.io.IOException;
> import java.net.InetSocketAddress;
> import java.net.Socket;
> import java.net.UnknownHostException;
> import java.util.Date;
> 
> /**
>  * @author       Benjamin Chevillon
>  */
> public class ConnectTest {
> 
>   private static Socket s;
> 
>   public static void main(String[] args) throws UnknownHostException,
> IOException {
>     
>     new SocketCloser().start();
>     s = new Socket();
>     try {
>       say("Opening socket");
>       s.connect(new InetSocketAddress("test.dyndns.org", 80), 10000);
>       say("Socket opened!");
>     } catch (IOException exc) {
>       say(" exception!");
>       exc.printStackTrace();
>     }
>     s.close();
>   }
>   
>   public static class SocketCloser extends Thread {
>     public void run() {
>       try {
>         try {
>           Thread.sleep(5000);
>         } catch (InterruptedException exc1) {
>           exc1.printStackTrace();
>         }
>         say(" closing");
>         ConnectTest.s.close();
>         say(" closed");
>       } catch (IOException exc) {
>         exc.printStackTrace();
>       }
>     }
>   }
>   
>   private static void say(String str) {
>     System.out.println(new Date() + " " + str);
>   }
> 
> }
> ---------------------------------------------
> Wed Jun 15 18:01:12 CEST 2005 Opening socket
> Wed Jun 15 18:01:17 CEST 2005  closing
> Wed Jun 15 18:01:17 CEST 2005  closed
> java.net.SocketException: Socket closed
> Wed Jun 15 18:01:17 CEST 2005  exception!
> 	at java.net.PlainSocketImpl.socketConnect(Native Method)
> 	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
> 	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
> 	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
> 	at java.net.Socket.connect(Socket.java:452)
> 	at ConnectTest.main(ConnectTest.java:49)
> 
> --------------------------------------------------------------------
> 
> 2005/6/15, Oleg Kalnichevski <ol...@apache.org>:
> > Benjamin,
> > 
> > Java (version 1.2 and below) does not seem to offer any other means to
> > interrupt a blocking I/O operation except for Socket#close. All
> > HttpMethod#abort can do is calling Connection#close, which in its turn
> > simply closes in sequence the output stream, the input stream and the
> > socket itself
> > 
> > http://jakarta.apache.org/commons/httpclient/3.0/xref/org/apache/commons/httpclient/HttpMethodBase.html#1007
> > http://jakarta.apache.org/commons/httpclient/3.0/xref/org/apache/commons/httpclient/HttpConnection.html#1141
> > 
> > Apparently the socket was blocked in the connect method while trying to
> > establish the connection with the target host (which in your case was
> > the proxy):
> > 
> > > org.apache.commons.httpclient.ConnectTimeoutException: The host did
> > > not accept the connection within timeout of 10000 ms
> > >        at
> > > org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
> > >        at
> > > org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)
> > 
> > So, technically speaking from the JRE perspective the socket was still
> > closed when HttpMethod#abort was attempted, hence Socket#close appears
> > to have made no effect on the blocked socket.
> > 
> > I am afraid there's not really much we can do here. The only resort
> > could possibly try would be calling Socket#shutdownInput through
> > reflection, but I suspect it will have no effect on sockets blocked
> > in the connect method either:
> > 
> > http://java.sun.com/j2se/1.4.2/docs/api/java/net/Socket.html#shutdownInput()
> > 
> > Oleg
> > 
> > On Wed, Jun 15, 2005 at 12:08:50PM +0200, Benjamin Chevillon wrote:
> > > Hello,
> > >
> > > I use HttpClient in my application to download description file. I
> > > work on ensuring that if the application gets closed, everything stop
> > > as fast as possible.
> > >
> > > I'm getting problem with this: as many companies network, http request
> > > get out through an http proxy. If I configure correctly the proxy
> > > settings, and if I try to abort a GetMethod, the connection is
> > > immediately stopped, no problem.
> > > Now if I don't configure the proxy settings, the abort method does not
> > > work, and my application hangs until timeout.
> > > As my application will be deployed on many networks on which I cannot
> > > be sure of the correct settings, I cannot accept that the application
> > > hangs until timeout.
> > >
> > > For better understanding, here is the unit case I'm using to test it
> > > (source code at the end of this email):
> > > There is two thread:
> > > - The main thread that starts the second one, sleeps for 3 seconds
> > > then aborts the second one.
> > > - The GetMethod thread that execute the GetMethod on a dummy site
> > > (http://test.dyndns.org does not work for me) that do not reply and
> > > timeouts in 10 seconds.
> > >
> > > Preliminary for testing:
> > > You must be on a network with a proxy. Configure the proxy settings at
> > > the beginning of the class.
> > >
> > > What do the test:
> > > It just gets http://test.dyndns.org
> > >
> > > Expected result:
> > > - http://test.dyndns.org does not reply correctly
> > > - so the execute wait for 10 seconds,
> > > - and the main method abort the GetMethod after only 3 seconds
> > > - So the application stops just after the abort and don't wait for 10 seconds.
> > >
> > > 1st test : with proxy settings.
> > > - uncomment the line "
> > > client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
> > > - Compile and start the class
> > >
> > > Result:
> > > - The application stops correctly in 3 seconds (just after the abort).
> > >
> > > 2nd test : without proxy settings.
> > > - comment the line "
> > > client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
> > > - Compile and start the class
> > >
> > > Result:
> > > - the abort method is executed in 3 seconds
> > > - BUT the execute method still hangs until the end of the 10 seconds timeout.
> > >
> > >
> > > Do anybody can produce the same type of acting?
> > > See below my test class and logs.
> > >
> > > Thanks in advance
> > >
> > > Benjamin Chevillon
> > > France T?l?com R&D
> > >
> > >
> > >
> > > ---------------------------------------------------------------
> > > File MethodAbortTest.java
> > >
> > > import java.io.IOException;
> > > import java.util.Date;
> > >
> > > import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
> > > import org.apache.commons.httpclient.HttpClient;
> > > import org.apache.commons.httpclient.HttpException;
> > > import org.apache.commons.httpclient.methods.GetMethod;
> > > import org.apache.commons.httpclient.params.HttpClientParams;
> > > import org.apache.commons.httpclient.params.HttpMethodParams;
> > >
> > > public class MethodAbortTest extends Thread {
> > >   public static final String PROXY_HOST = "proxy";
> > >   public static final int PROXY_PORT = 8080;
> > >   // An url that do not reply
> > >   public static final String GETURL = "http://test.dyndns.org/";
> > >
> > >   HttpClient client;
> > >
> > >
> > >   private GetMethod get;
> > >
> > >   public static void main(String[] args) {
> > >     System.setProperty("org.apache.commons.logging.Log",
> > > "org.apache.commons.logging.impl.SimpleLog");
> > >     System.setProperty("org.apache.commons.logging.simplelog.showdatetime",
> > > "true");
> > >     System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire.header",
> > > "debug");
> > >     System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient",
> > > "debug");
> > >
> > >     MethodAbortTest myTest = new MethodAbortTest();
> > >     myTest.start();
> > >
> > >     System.out.println("done");
> > >     try {
> > >       Thread.sleep(3000);
> > >     } catch (InterruptedException exc) {
> > >       exc.printStackTrace();
> > >     }
> > >
> > >     myTest.cancel();
> > >   }
> > >
> > >   public void run() {
> > >     HttpClientParams params = new HttpClientParams();
> > >     params.setParameter(HttpMethodParams.RETRY_HANDLER,
> > >         new DefaultHttpMethodRetryHandler(0, true));
> > >
> > >
> > >     client = new HttpClient(params);
> > >     client.getHttpConnectionManager().getParams().setConnectionTimeout(10000);
> > >     // Comment next line to unconfigure proxy settings
> > >     client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
> > >
> > >     get = new GetMethod(GETURL);
> > >
> > >     try {
> > >       System.out.println(new Date() + " execute");
> > >       int statuscode = client.executeMethod(get);
> > >       System.out.println(statuscode);
> > >       System.out.println("execution done");
> > >       // print response to stdout
> > >       System.out.println(get.getResponseBodyAsString());
> > >     } catch (HttpException exc) {
> > >       // TODO Auto-generated catch block
> > >       exc.printStackTrace();
> > >     } catch (IOException exc) {
> > >       // TODO Auto-generated catch block
> > >       System.out.println("IO");
> > >       exc.printStackTrace();
> > >     } finally {
> > >       // be sure the connection is released back to the connection
> > >       // manager
> > >       System.out.println("End Of HttpGet");
> > >       get.releaseConnection();
> > >     }
> > >   }
> > >
> > >   public void cancel() {
> > >     //      this.interrupt();
> > >     System.out.println(new Date() + " canceling");
> > >     get.abort();
> > >     System.out.println("aborted?" + get.isAborted());
> > >   }
> > > }
> > >
> > > ---------------------------------------------------
> > > With correct proxy setting, the class aborts immediately
> > >
> > > done
> > > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.useragent = Jakarta Commons-HttpClient/3.0-rc2
> > > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.version = HTTP/1.1
> > > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.connection-manager.class = class
> > > org.apache.commons.httpclient.SimpleHttpConnectionManager
> > > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.cookie-policy = rfc2109
> > > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.element-charset = US-ASCII
> > > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.content-charset = ISO-8859-1
> > > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.method.retry-handler =
> > > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
> > > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
> > > dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
> > > HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
> > > EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
> > > dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
> > > HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
> > > dd-MM-yyyy HH:mm:ss z]
> > > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.method.retry-handler =
> > > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java vendor: Sun
> > > Microsystems Inc.
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
> > > C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
> > > name: Windows XP
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
> > > architecture: x86
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system version: 5.1
> > > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
> > > key/parameter generation; DSA signing; SHA-1, MD5 digests;
> > > SecureRandom; X.509 certificates; JKS keystore; PKIX
> > > CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
> > > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
> > > JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
> > > factories, SSLv3, TLSv1)
> > > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
> > > SUN's provider for RSA signatures
> > > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
> > > Provider (implements DES, Triple DES, AES, Blowfish, PBE,
> > > Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
> > > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
> > > 2005/06/15 10:50:57:207 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.connection.timeout = 10000
> > > Wed Jun 15 10:50:57 CEST 2005 execute
> > > 2005/06/15 10:50:57:394 CEST [DEBUG] HttpConnection - Open connection
> > > to proxy:8080
> > > 2005/06/15 10:50:57:425 CEST [DEBUG] header - >> "GET
> > > http://test.dyndns.org/ HTTP/1.1[\r][\n]"
> > > 2005/06/15 10:50:57:441 CEST [DEBUG] HttpMethodBase - Adding Host request header
> > > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "User-Agent: Jakarta
> > > Commons-HttpClient/3.0-rc2[\r][\n]"
> > > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Host: test.dyndns.org[\r][\n]"
> > > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Proxy-Connection:
> > > Keep-Alive[\r][\n]"
> > > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "[\r][\n]"
> > > Wed Jun 15 10:50:59 CEST 2005 canceling
> > > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Closing the
> > > connection.
> > > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Method retry
> > > handler returned false. Automatic recovery will not be attempted
> > > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
> > > connection back to connection manager.
> > > IO
> > > java.net.SocketException: socket closed
> > >       at java.net.SocketInputStream.socketRead0(Native Method)
> > >       at java.net.SocketInputStream.read(SocketInputStream.java:129)
> > >       at java.io.BufferedInputStream.fill(BufferedInputStream.java:183)
> > >       at java.io.BufferedInputStream.read(BufferedInputStream.java:201)
> > >       at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:77)
> > >       at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:105)
> > >       at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1110)
> > >       at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1824)
> > >       at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1584)
> > >       at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:995)
> > >       at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:393)
> > > End Of HttpGet        at
> > > org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
> > >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
> > >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
> > >       at MethodAbortTest.run(MethodAbortTest.java:86)
> > > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
> > > connection back to connection manager.
> > >
> > > aborted?true
> > >
> > > ---------------------------------------------------
> > > Without proxy, class hangs for 10 seconds
> > >
> > > done
> > > 2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.useragent = Jakarta Commons-HttpClient/3.0-rc2
> > > 2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.version = HTTP/1.1
> > > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.connection-manager.class = class
> > > org.apache.commons.httpclient.SimpleHttpConnectionManager
> > > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.cookie-policy = rfc2109
> > > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.element-charset = US-ASCII
> > > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.protocol.content-charset = ISO-8859-1
> > > 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.method.retry-handler =
> > > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
> > > 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
> > > dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
> > > HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
> > > EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
> > > dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
> > > HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
> > > dd-MM-yyyy HH:mm:ss z]
> > > 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.method.retry-handler =
> > > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
> > > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
> > > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java vendor: Sun
> > > Microsystems Inc.
> > > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
> > > C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
> > > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
> > > name: Windows XP
> > > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
> > > architecture: x86
> > > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system version: 5.1
> > > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
> > > key/parameter generation; DSA signing; SHA-1, MD5 digests;
> > > SecureRandom; X.509 certificates; JKS keystore; PKIX
> > > CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
> > > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
> > > JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
> > > factories, SSLv3, TLSv1)
> > > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
> > > SUN's provider for RSA signatures
> > > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
> > > Provider (implements DES, Triple DES, AES, Blowfish, PBE,
> > > Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
> > > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
> > > 2005/06/15 10:54:02:989 CEST [DEBUG] DefaultHttpParams - Set parameter
> > > http.connection.timeout = 10000
> > > Wed Jun 15 10:54:03 CEST 2005 execute
> > > 2005/06/15 10:54:03:098 CEST [DEBUG] HttpConnection - Open connection
> > > to test.dyndns.org:80
> > > Wed Jun 15 10:54:05 CEST 2005 canceling
> > > aborted?true
> > > IO
> > > 2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Closing the
> > > connection.
> > > 2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Method retry
> > > handler returned false. Automatic recovery will not be attempted
> > > 2005/06/15 10:54:13:270 CEST [DEBUG] HttpConnection - Releasing
> > > connection back to connection manager.
> > > org.apache.commons.httpclient.ConnectTimeoutException: The host did
> > > not accept the connection within timeout of 10000 ms
> > >       at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
> > >       at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)
> > >       at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:704)
> > >       at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:382)
> > >       at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
> > >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
> > >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
> > >       at MethodAbortTest.run(MethodAbortTest.java:86)
> > > Caused by: java.net.SocketTimeoutException: connect timed out
> > >       at java.net.PlainSocketImpl.socketConnect(Native Method)
> > >       at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
> > >       at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
> > >       at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
> > >       at java.net.Socket.connect(Socket.java:452)
> > >       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> > >       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)End
> > > Of HttpGet
> > >
> > >       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> > >       at java.lang.reflect.Method.invoke(Method.java:324)
> > >       at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:139)
> > >       ... 7 more
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: httpclient-user-help@jakarta.apache.org
> > >
> > 
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: httpclient-user-help@jakarta.apache.org
> > 
> >
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: httpclient-user-help@jakarta.apache.org
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: httpclient-user-help@jakarta.apache.org


Re: Abort HttpMethod hangs due to bad proxy config

Posted by Benjamin Chevillon <bc...@gmail.com>.
Thank you for your precise and quick reply.
Encourage by this precision, I downloaded the source code and traced it.
Maybe this email should be posted to dev mailing list, except if this
question has already been fixed.

Indeed, the client.executeMethod hangs in
org.apache.commons.httpclient.protocol.ReflectionSocketFactory where
the socket is opened. It hangs on the line 139 in the trunk CVS
138 SOCKETBIND_METHOD.invoke(socket, new Object[] { localaddr});
139 SOCKETCONNECT_METHOD.invoke(socket, new Object[] { remoteaddr, new
Integer(timeout)});
These 2 lines are similar to 
        //  socket.bind(localaddr);
        //  socket.connect(remoteaddr, timeout);

But I was puzzled when you say that we cannot do much against it,
because, we can cancel some similar problem on web browser and it
takes effect immediately.

Actually, the socket.connect() method can be canceled with
socket.close(): see the class attached: a socket is opened with a 10
seconds timeout and a second thread close it only 5 seconds later. It
works. (sorry for the quick & dirty style of the class)

It does not work on HttpClient, because the abort() method close only
the InputStream which is not already created at this moment (since the
socket hangs on opening).
There are 2 problems:
- the socket is open within the same call of its creation (so we don't
have a pointer to it, to close it).
- the abort() method has no way to call the close() method deeply.

The chain of call is here:
HttpClient.executeMethod() ->...-> HttpConnection.open() ->
DefaultSocketFactory.createSocket() ->
ReflectionSocketFactory.createSocket()

The public class closest to Socket is HttpConnection. A socket is
created with the open() method. It calls
ReflectionSocketFactory.createSocket() but inside this method the
socket.bind(..) and socket.connect(..) methods are not separated and
hangs. Thus, the HttpConnection.open() method never returns and the
HttpConnection cannot close() the socket (since it socket variable is
null).

To resolve it, there should be 2 calls to ReflectionSocketFactory in
HttpConnection:
- One to create the socket (until bind). This method always return
immediately and this way, we could have a variable that points to the
Socket instance.
- A second call to connect the socket.
If the second call hangs, then we could call HttpConnection.close()
since the socket variable is not null.

Finally, there should be a way to for the HttpClient to close the
HttpConnection which concerns it.

What do you think about this? Tell me if I am wrong.

Thanks

Benjamin

------------------------
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;

/**
 * @author       Benjamin Chevillon
 */
public class ConnectTest {

  private static Socket s;

  public static void main(String[] args) throws UnknownHostException,
IOException {
    
    new SocketCloser().start();
    s = new Socket();
    try {
      say("Opening socket");
      s.connect(new InetSocketAddress("test.dyndns.org", 80), 10000);
      say("Socket opened!");
    } catch (IOException exc) {
      say(" exception!");
      exc.printStackTrace();
    }
    s.close();
  }
  
  public static class SocketCloser extends Thread {
    public void run() {
      try {
        try {
          Thread.sleep(5000);
        } catch (InterruptedException exc1) {
          exc1.printStackTrace();
        }
        say(" closing");
        ConnectTest.s.close();
        say(" closed");
      } catch (IOException exc) {
        exc.printStackTrace();
      }
    }
  }
  
  private static void say(String str) {
    System.out.println(new Date() + " " + str);
  }

}
---------------------------------------------
Wed Jun 15 18:01:12 CEST 2005 Opening socket
Wed Jun 15 18:01:17 CEST 2005  closing
Wed Jun 15 18:01:17 CEST 2005  closed
java.net.SocketException: Socket closed
Wed Jun 15 18:01:17 CEST 2005  exception!
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
	at java.net.Socket.connect(Socket.java:452)
	at ConnectTest.main(ConnectTest.java:49)

--------------------------------------------------------------------

2005/6/15, Oleg Kalnichevski <ol...@apache.org>:
> Benjamin,
> 
> Java (version 1.2 and below) does not seem to offer any other means to
> interrupt a blocking I/O operation except for Socket#close. All
> HttpMethod#abort can do is calling Connection#close, which in its turn
> simply closes in sequence the output stream, the input stream and the
> socket itself
> 
> http://jakarta.apache.org/commons/httpclient/3.0/xref/org/apache/commons/httpclient/HttpMethodBase.html#1007
> http://jakarta.apache.org/commons/httpclient/3.0/xref/org/apache/commons/httpclient/HttpConnection.html#1141
> 
> Apparently the socket was blocked in the connect method while trying to
> establish the connection with the target host (which in your case was
> the proxy):
> 
> > org.apache.commons.httpclient.ConnectTimeoutException: The host did
> > not accept the connection within timeout of 10000 ms
> >        at
> > org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
> >        at
> > org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)
> 
> So, technically speaking from the JRE perspective the socket was still
> closed when HttpMethod#abort was attempted, hence Socket#close appears
> to have made no effect on the blocked socket.
> 
> I am afraid there's not really much we can do here. The only resort
> could possibly try would be calling Socket#shutdownInput through
> reflection, but I suspect it will have no effect on sockets blocked
> in the connect method either:
> 
> http://java.sun.com/j2se/1.4.2/docs/api/java/net/Socket.html#shutdownInput()
> 
> Oleg
> 
> On Wed, Jun 15, 2005 at 12:08:50PM +0200, Benjamin Chevillon wrote:
> > Hello,
> >
> > I use HttpClient in my application to download description file. I
> > work on ensuring that if the application gets closed, everything stop
> > as fast as possible.
> >
> > I'm getting problem with this: as many companies network, http request
> > get out through an http proxy. If I configure correctly the proxy
> > settings, and if I try to abort a GetMethod, the connection is
> > immediately stopped, no problem.
> > Now if I don't configure the proxy settings, the abort method does not
> > work, and my application hangs until timeout.
> > As my application will be deployed on many networks on which I cannot
> > be sure of the correct settings, I cannot accept that the application
> > hangs until timeout.
> >
> > For better understanding, here is the unit case I'm using to test it
> > (source code at the end of this email):
> > There is two thread:
> > - The main thread that starts the second one, sleeps for 3 seconds
> > then aborts the second one.
> > - The GetMethod thread that execute the GetMethod on a dummy site
> > (http://test.dyndns.org does not work for me) that do not reply and
> > timeouts in 10 seconds.
> >
> > Preliminary for testing:
> > You must be on a network with a proxy. Configure the proxy settings at
> > the beginning of the class.
> >
> > What do the test:
> > It just gets http://test.dyndns.org
> >
> > Expected result:
> > - http://test.dyndns.org does not reply correctly
> > - so the execute wait for 10 seconds,
> > - and the main method abort the GetMethod after only 3 seconds
> > - So the application stops just after the abort and don't wait for 10 seconds.
> >
> > 1st test : with proxy settings.
> > - uncomment the line "
> > client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
> > - Compile and start the class
> >
> > Result:
> > - The application stops correctly in 3 seconds (just after the abort).
> >
> > 2nd test : without proxy settings.
> > - comment the line "
> > client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
> > - Compile and start the class
> >
> > Result:
> > - the abort method is executed in 3 seconds
> > - BUT the execute method still hangs until the end of the 10 seconds timeout.
> >
> >
> > Do anybody can produce the same type of acting?
> > See below my test class and logs.
> >
> > Thanks in advance
> >
> > Benjamin Chevillon
> > France T?l?com R&D
> >
> >
> >
> > ---------------------------------------------------------------
> > File MethodAbortTest.java
> >
> > import java.io.IOException;
> > import java.util.Date;
> >
> > import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
> > import org.apache.commons.httpclient.HttpClient;
> > import org.apache.commons.httpclient.HttpException;
> > import org.apache.commons.httpclient.methods.GetMethod;
> > import org.apache.commons.httpclient.params.HttpClientParams;
> > import org.apache.commons.httpclient.params.HttpMethodParams;
> >
> > public class MethodAbortTest extends Thread {
> >   public static final String PROXY_HOST = "proxy";
> >   public static final int PROXY_PORT = 8080;
> >   // An url that do not reply
> >   public static final String GETURL = "http://test.dyndns.org/";
> >
> >   HttpClient client;
> >
> >
> >   private GetMethod get;
> >
> >   public static void main(String[] args) {
> >     System.setProperty("org.apache.commons.logging.Log",
> > "org.apache.commons.logging.impl.SimpleLog");
> >     System.setProperty("org.apache.commons.logging.simplelog.showdatetime",
> > "true");
> >     System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire.header",
> > "debug");
> >     System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient",
> > "debug");
> >
> >     MethodAbortTest myTest = new MethodAbortTest();
> >     myTest.start();
> >
> >     System.out.println("done");
> >     try {
> >       Thread.sleep(3000);
> >     } catch (InterruptedException exc) {
> >       exc.printStackTrace();
> >     }
> >
> >     myTest.cancel();
> >   }
> >
> >   public void run() {
> >     HttpClientParams params = new HttpClientParams();
> >     params.setParameter(HttpMethodParams.RETRY_HANDLER,
> >         new DefaultHttpMethodRetryHandler(0, true));
> >
> >
> >     client = new HttpClient(params);
> >     client.getHttpConnectionManager().getParams().setConnectionTimeout(10000);
> >     // Comment next line to unconfigure proxy settings
> >     client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
> >
> >     get = new GetMethod(GETURL);
> >
> >     try {
> >       System.out.println(new Date() + " execute");
> >       int statuscode = client.executeMethod(get);
> >       System.out.println(statuscode);
> >       System.out.println("execution done");
> >       // print response to stdout
> >       System.out.println(get.getResponseBodyAsString());
> >     } catch (HttpException exc) {
> >       // TODO Auto-generated catch block
> >       exc.printStackTrace();
> >     } catch (IOException exc) {
> >       // TODO Auto-generated catch block
> >       System.out.println("IO");
> >       exc.printStackTrace();
> >     } finally {
> >       // be sure the connection is released back to the connection
> >       // manager
> >       System.out.println("End Of HttpGet");
> >       get.releaseConnection();
> >     }
> >   }
> >
> >   public void cancel() {
> >     //      this.interrupt();
> >     System.out.println(new Date() + " canceling");
> >     get.abort();
> >     System.out.println("aborted?" + get.isAborted());
> >   }
> > }
> >
> > ---------------------------------------------------
> > With correct proxy setting, the class aborts immediately
> >
> > done
> > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.useragent = Jakarta Commons-HttpClient/3.0-rc2
> > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.version = HTTP/1.1
> > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.connection-manager.class = class
> > org.apache.commons.httpclient.SimpleHttpConnectionManager
> > 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.cookie-policy = rfc2109
> > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.element-charset = US-ASCII
> > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.content-charset = ISO-8859-1
> > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.method.retry-handler =
> > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
> > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
> > dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
> > HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
> > EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
> > dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
> > HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
> > dd-MM-yyyy HH:mm:ss z]
> > 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.method.retry-handler =
> > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java vendor: Sun
> > Microsystems Inc.
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
> > C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
> > name: Windows XP
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
> > architecture: x86
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system version: 5.1
> > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
> > key/parameter generation; DSA signing; SHA-1, MD5 digests;
> > SecureRandom; X.509 certificates; JKS keystore; PKIX
> > CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
> > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
> > JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
> > factories, SSLv3, TLSv1)
> > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
> > SUN's provider for RSA signatures
> > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
> > Provider (implements DES, Triple DES, AES, Blowfish, PBE,
> > Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
> > 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
> > 2005/06/15 10:50:57:207 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.connection.timeout = 10000
> > Wed Jun 15 10:50:57 CEST 2005 execute
> > 2005/06/15 10:50:57:394 CEST [DEBUG] HttpConnection - Open connection
> > to proxy:8080
> > 2005/06/15 10:50:57:425 CEST [DEBUG] header - >> "GET
> > http://test.dyndns.org/ HTTP/1.1[\r][\n]"
> > 2005/06/15 10:50:57:441 CEST [DEBUG] HttpMethodBase - Adding Host request header
> > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "User-Agent: Jakarta
> > Commons-HttpClient/3.0-rc2[\r][\n]"
> > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Host: test.dyndns.org[\r][\n]"
> > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Proxy-Connection:
> > Keep-Alive[\r][\n]"
> > 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "[\r][\n]"
> > Wed Jun 15 10:50:59 CEST 2005 canceling
> > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Closing the
> > connection.
> > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Method retry
> > handler returned false. Automatic recovery will not be attempted
> > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
> > connection back to connection manager.
> > IO
> > java.net.SocketException: socket closed
> >       at java.net.SocketInputStream.socketRead0(Native Method)
> >       at java.net.SocketInputStream.read(SocketInputStream.java:129)
> >       at java.io.BufferedInputStream.fill(BufferedInputStream.java:183)
> >       at java.io.BufferedInputStream.read(BufferedInputStream.java:201)
> >       at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:77)
> >       at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:105)
> >       at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1110)
> >       at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1824)
> >       at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1584)
> >       at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:995)
> >       at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:393)
> > End Of HttpGet        at
> > org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
> >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
> >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
> >       at MethodAbortTest.run(MethodAbortTest.java:86)
> > 2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
> > connection back to connection manager.
> >
> > aborted?true
> >
> > ---------------------------------------------------
> > Without proxy, class hangs for 10 seconds
> >
> > done
> > 2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.useragent = Jakarta Commons-HttpClient/3.0-rc2
> > 2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.version = HTTP/1.1
> > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.connection-manager.class = class
> > org.apache.commons.httpclient.SimpleHttpConnectionManager
> > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.cookie-policy = rfc2109
> > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.element-charset = US-ASCII
> > 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.protocol.content-charset = ISO-8859-1
> > 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.method.retry-handler =
> > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
> > 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
> > dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
> > HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
> > EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
> > dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
> > HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
> > dd-MM-yyyy HH:mm:ss z]
> > 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.method.retry-handler =
> > org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
> > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
> > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java vendor: Sun
> > Microsystems Inc.
> > 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
> > C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
> > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
> > name: Windows XP
> > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
> > architecture: x86
> > 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system version: 5.1
> > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
> > key/parameter generation; DSA signing; SHA-1, MD5 digests;
> > SecureRandom; X.509 certificates; JKS keystore; PKIX
> > CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
> > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
> > JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
> > factories, SSLv3, TLSv1)
> > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
> > SUN's provider for RSA signatures
> > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
> > Provider (implements DES, Triple DES, AES, Blowfish, PBE,
> > Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
> > 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
> > 2005/06/15 10:54:02:989 CEST [DEBUG] DefaultHttpParams - Set parameter
> > http.connection.timeout = 10000
> > Wed Jun 15 10:54:03 CEST 2005 execute
> > 2005/06/15 10:54:03:098 CEST [DEBUG] HttpConnection - Open connection
> > to test.dyndns.org:80
> > Wed Jun 15 10:54:05 CEST 2005 canceling
> > aborted?true
> > IO
> > 2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Closing the
> > connection.
> > 2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Method retry
> > handler returned false. Automatic recovery will not be attempted
> > 2005/06/15 10:54:13:270 CEST [DEBUG] HttpConnection - Releasing
> > connection back to connection manager.
> > org.apache.commons.httpclient.ConnectTimeoutException: The host did
> > not accept the connection within timeout of 10000 ms
> >       at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
> >       at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)
> >       at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:704)
> >       at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:382)
> >       at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
> >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
> >       at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
> >       at MethodAbortTest.run(MethodAbortTest.java:86)
> > Caused by: java.net.SocketTimeoutException: connect timed out
> >       at java.net.PlainSocketImpl.socketConnect(Native Method)
> >       at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
> >       at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
> >       at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
> >       at java.net.Socket.connect(Socket.java:452)
> >       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> >       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)End
> > Of HttpGet
> >
> >       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> >       at java.lang.reflect.Method.invoke(Method.java:324)
> >       at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:139)
> >       ... 7 more
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: httpclient-user-help@jakarta.apache.org
> >
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: httpclient-user-help@jakarta.apache.org
> 
>

---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: httpclient-user-help@jakarta.apache.org


Re: Abort HttpMethod hangs due to bad proxy config

Posted by Oleg Kalnichevski <ol...@apache.org>.
Benjamin,

Java (version 1.2 and below) does not seem to offer any other means to
interrupt a blocking I/O operation except for Socket#close. All
HttpMethod#abort can do is calling Connection#close, which in its turn
simply closes in sequence the output stream, the input stream and the
socket itself

http://jakarta.apache.org/commons/httpclient/3.0/xref/org/apache/commons/httpclient/HttpMethodBase.html#1007
http://jakarta.apache.org/commons/httpclient/3.0/xref/org/apache/commons/httpclient/HttpConnection.html#1141

Apparently the socket was blocked in the connect method while trying to
establish the connection with the target host (which in your case was
the proxy): 

> org.apache.commons.httpclient.ConnectTimeoutException: The host did
> not accept the connection within timeout of 10000 ms
>        at 
> org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
>        at 
> org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)

So, technically speaking from the JRE perspective the socket was still
closed when HttpMethod#abort was attempted, hence Socket#close appears 
to have made no effect on the blocked socket.

I am afraid there's not really much we can do here. The only resort
could possibly try would be calling Socket#shutdownInput through
reflection, but I suspect it will have no effect on sockets blocked
in the connect method either:

http://java.sun.com/j2se/1.4.2/docs/api/java/net/Socket.html#shutdownInput()

Oleg

On Wed, Jun 15, 2005 at 12:08:50PM +0200, Benjamin Chevillon wrote:
> Hello,
> 
> I use HttpClient in my application to download description file. I
> work on ensuring that if the application gets closed, everything stop
> as fast as possible.
> 
> I'm getting problem with this: as many companies network, http request
> get out through an http proxy. If I configure correctly the proxy
> settings, and if I try to abort a GetMethod, the connection is
> immediately stopped, no problem.
> Now if I don't configure the proxy settings, the abort method does not
> work, and my application hangs until timeout.
> As my application will be deployed on many networks on which I cannot
> be sure of the correct settings, I cannot accept that the application
> hangs until timeout.
> 
> For better understanding, here is the unit case I'm using to test it
> (source code at the end of this email):
> There is two thread:
> - The main thread that starts the second one, sleeps for 3 seconds
> then aborts the second one.
> - The GetMethod thread that execute the GetMethod on a dummy site
> (http://test.dyndns.org does not work for me) that do not reply and
> timeouts in 10 seconds.
> 
> Preliminary for testing:
> You must be on a network with a proxy. Configure the proxy settings at
> the beginning of the class.
> 
> What do the test:
> It just gets http://test.dyndns.org
> 
> Expected result:
> - http://test.dyndns.org does not reply correctly
> - so the execute wait for 10 seconds,
> - and the main method abort the GetMethod after only 3 seconds
> - So the application stops just after the abort and don't wait for 10 seconds.
> 
> 1st test : with proxy settings.
> - uncomment the line "   
> client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
> - Compile and start the class
> 
> Result:
> - The application stops correctly in 3 seconds (just after the abort).
> 
> 2nd test : without proxy settings.
> - comment the line "   
> client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);"
> - Compile and start the class
> 
> Result:
> - the abort method is executed in 3 seconds
> - BUT the execute method still hangs until the end of the 10 seconds timeout.
> 
> 
> Do anybody can produce the same type of acting?
> See below my test class and logs.
> 
> Thanks in advance
> 
> Benjamin Chevillon
> France T?l?com R&D
> 
> 
> 
> ---------------------------------------------------------------
> File MethodAbortTest.java
> 
> import java.io.IOException;
> import java.util.Date;
> 
> import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
> import org.apache.commons.httpclient.HttpClient;
> import org.apache.commons.httpclient.HttpException;
> import org.apache.commons.httpclient.methods.GetMethod;
> import org.apache.commons.httpclient.params.HttpClientParams;
> import org.apache.commons.httpclient.params.HttpMethodParams;
> 
> public class MethodAbortTest extends Thread {
>   public static final String PROXY_HOST = "proxy";
>   public static final int PROXY_PORT = 8080;
>   // An url that do not reply
>   public static final String GETURL = "http://test.dyndns.org/";
>   
>   HttpClient client;
>   
> 
>   private GetMethod get;
> 
>   public static void main(String[] args) {
>     System.setProperty("org.apache.commons.logging.Log",
> "org.apache.commons.logging.impl.SimpleLog");
>     System.setProperty("org.apache.commons.logging.simplelog.showdatetime",
> "true");
>     System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire.header",
> "debug");
>     System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient",
> "debug");
>     
>     MethodAbortTest myTest = new MethodAbortTest();
>     myTest.start();
>     
>     System.out.println("done");
>     try {
>       Thread.sleep(3000);
>     } catch (InterruptedException exc) {
>       exc.printStackTrace();
>     }
> 
>     myTest.cancel();
>   }
>   
>   public void run() {
>     HttpClientParams params = new HttpClientParams();
>     params.setParameter(HttpMethodParams.RETRY_HANDLER,
>         new DefaultHttpMethodRetryHandler(0, true));
>     
> 
>     client = new HttpClient(params);
>     client.getHttpConnectionManager().getParams().setConnectionTimeout(10000);
>     // Comment next line to unconfigure proxy settings
>     client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
>     
>     get = new GetMethod(GETURL);
> 
>     try {
>       System.out.println(new Date() + " execute");
>       int statuscode = client.executeMethod(get);
>       System.out.println(statuscode);
>       System.out.println("execution done");
>       // print response to stdout
>       System.out.println(get.getResponseBodyAsString());
>     } catch (HttpException exc) {
>       // TODO Auto-generated catch block
>       exc.printStackTrace();
>     } catch (IOException exc) {
>       // TODO Auto-generated catch block
>       System.out.println("IO");
>       exc.printStackTrace();
>     } finally {
>       // be sure the connection is released back to the connection 
>       // manager
>       System.out.println("End Of HttpGet");
>       get.releaseConnection();
>     }
>   }
> 
>   public void cancel() {
>     //      this.interrupt();
>     System.out.println(new Date() + " canceling");
>     get.abort();
>     System.out.println("aborted?" + get.isAborted());
>   }
> }
> 
> ---------------------------------------------------
> With correct proxy setting, the class aborts immediately
> 
> done
> 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.useragent = Jakarta Commons-HttpClient/3.0-rc2
> 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.version = HTTP/1.1
> 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.connection-manager.class = class
> org.apache.commons.httpclient.SimpleHttpConnectionManager
> 2005/06/15 10:50:56:988 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.cookie-policy = rfc2109
> 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.element-charset = US-ASCII
> 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.content-charset = ISO-8859-1
> 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.method.retry-handler =
> org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
> 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
> dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
> HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
> EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
> dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
> HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
> dd-MM-yyyy HH:mm:ss z]
> 2005/06/15 10:50:57:003 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.method.retry-handler =
> org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java vendor: Sun
> Microsystems Inc.
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
> C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
> name: Windows XP
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system
> architecture: x86
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Operating system version: 5.1
> 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
> key/parameter generation; DSA signing; SHA-1, MD5 digests;
> SecureRandom; X.509 certificates; JKS keystore; PKIX
> CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
> 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
> JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
> factories, SSLv3, TLSv1)
> 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
> SUN's provider for RSA signatures
> 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
> Provider (implements DES, Triple DES, AES, Blowfish, PBE,
> Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
> 2005/06/15 10:50:57:191 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
> 2005/06/15 10:50:57:207 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.connection.timeout = 10000
> Wed Jun 15 10:50:57 CEST 2005 execute
> 2005/06/15 10:50:57:394 CEST [DEBUG] HttpConnection - Open connection
> to proxy:8080
> 2005/06/15 10:50:57:425 CEST [DEBUG] header - >> "GET
> http://test.dyndns.org/ HTTP/1.1[\r][\n]"
> 2005/06/15 10:50:57:441 CEST [DEBUG] HttpMethodBase - Adding Host request header
> 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "User-Agent: Jakarta
> Commons-HttpClient/3.0-rc2[\r][\n]"
> 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Host: test.dyndns.org[\r][\n]"
> 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "Proxy-Connection:
> Keep-Alive[\r][\n]"
> 2005/06/15 10:50:57:457 CEST [DEBUG] header - >> "[\r][\n]"
> Wed Jun 15 10:50:59 CEST 2005 canceling
> 2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Closing the
> connection.
> 2005/06/15 10:50:59:878 CEST [DEBUG] HttpMethodDirector - Method retry
> handler returned false. Automatic recovery will not be attempted
> 2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
> connection back to connection manager.
> IO
> java.net.SocketException: socket closed
> 	at java.net.SocketInputStream.socketRead0(Native Method)
> 	at java.net.SocketInputStream.read(SocketInputStream.java:129)
> 	at java.io.BufferedInputStream.fill(BufferedInputStream.java:183)
> 	at java.io.BufferedInputStream.read(BufferedInputStream.java:201)
> 	at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:77)
> 	at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:105)
> 	at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1110)
> 	at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1824)
> 	at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1584)
> 	at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:995)
> 	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:393)
> End Of HttpGet	at
> org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
> 	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
> 	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
> 	at MethodAbortTest.run(MethodAbortTest.java:86)
> 2005/06/15 10:50:59:878 CEST [DEBUG] HttpConnection - Releasing
> connection back to connection manager.
> 
> aborted?true
> 
> ---------------------------------------------------
> Without proxy, class hangs for 10 seconds
> 
> done
> 2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.useragent = Jakarta Commons-HttpClient/3.0-rc2
> 2005/06/15 10:54:02:661 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.version = HTTP/1.1
> 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.connection-manager.class = class
> org.apache.commons.httpclient.SimpleHttpConnectionManager
> 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.cookie-policy = rfc2109
> 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.element-charset = US-ASCII
> 2005/06/15 10:54:02:676 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.protocol.content-charset = ISO-8859-1
> 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.method.retry-handler =
> org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@167d940
> 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.dateparser.patterns = [EEE, dd MMM yyyy HH:mm:ss zzz, EEEE,
> dd-MMM-yy HH:mm:ss zzz, EEE MMM d HH:mm:ss yyyy, EEE, dd-MMM-yyyy
> HH:mm:ss z, EEE, dd-MMM-yyyy HH-mm-ss z, EEE, dd MMM yy HH:mm:ss z,
> EEE dd-MMM-yyyy HH:mm:ss z, EEE dd MMM yyyy HH:mm:ss z, EEE
> dd-MMM-yyyy HH-mm-ss z, EEE dd-MMM-yy HH:mm:ss z, EEE dd MMM yy
> HH:mm:ss z, EEE,dd-MMM-yy HH:mm:ss z, EEE,dd-MMM-yyyy HH:mm:ss z, EEE,
> dd-MM-yyyy HH:mm:ss z]
> 2005/06/15 10:54:02:692 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.method.retry-handler =
> org.apache.commons.httpclient.DefaultHttpMethodRetryHandler@fd13b5
> 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java version: 1.4.2_07
> 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Java vendor: Sun
> Microsystems Inc.
> 2005/06/15 10:50:57:019 CEST [DEBUG] HttpClient - Java class path:
> C:\workspace\Temp\Dev\classes;C:\workspace\Temp\Dev\lib\commons-codec-1.3.jar;C:\workspace\Temp\Dev\lib\commons-httpclient-3.0-rc2.jar;C:\workspace\Temp\Dev\lib\commons-logging.jar
> 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
> name: Windows XP
> 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system
> architecture: x86
> 2005/06/15 10:54:02:801 CEST [DEBUG] HttpClient - Operating system version: 5.1
> 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SUN 1.42: SUN (DSA
> key/parameter generation; DSA signing; SHA-1, MD5 digests;
> SecureRandom; X.509 certificates; JKS keystore; PKIX
> CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
> 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJSSE 1.42: Sun
> JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
> factories, SSLv3, TLSv1)
> 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunRsaSign 1.42:
> SUN's provider for RSA signatures
> 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJCE 1.42: SunJCE
> Provider (implements DES, Triple DES, AES, Blowfish, PBE,
> Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
> 2005/06/15 10:54:02:973 CEST [DEBUG] HttpClient - SunJGSS 1.0: Sun (Kerberos v5)
> 2005/06/15 10:54:02:989 CEST [DEBUG] DefaultHttpParams - Set parameter
> http.connection.timeout = 10000
> Wed Jun 15 10:54:03 CEST 2005 execute
> 2005/06/15 10:54:03:098 CEST [DEBUG] HttpConnection - Open connection
> to test.dyndns.org:80
> Wed Jun 15 10:54:05 CEST 2005 canceling
> aborted?true
> IO
> 2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Closing the
> connection.
> 2005/06/15 10:54:13:270 CEST [DEBUG] HttpMethodDirector - Method retry
> handler returned false. Automatic recovery will not be attempted
> 2005/06/15 10:54:13:270 CEST [DEBUG] HttpConnection - Releasing
> connection back to connection manager.
> org.apache.commons.httpclient.ConnectTimeoutException: The host did
> not accept the connection within timeout of 10000 ms
> 	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:154)
> 	at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:124)
> 	at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:704)
> 	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:382)
> 	at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:168)
> 	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:393)
> 	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
> 	at MethodAbortTest.run(MethodAbortTest.java:86)
> Caused by: java.net.SocketTimeoutException: connect timed out
> 	at java.net.PlainSocketImpl.socketConnect(Native Method)
> 	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
> 	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
> 	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
> 	at java.net.Socket.connect(Socket.java:452)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)End
> Of HttpGet
> 
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> 	at java.lang.reflect.Method.invoke(Method.java:324)
> 	at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:139)
> 	... 7 more
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: httpclient-user-help@jakarta.apache.org
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: httpclient-user-help@jakarta.apache.org