HttpURLConnection timeout solution

N

Niels Campbell

After spending nearly 3 days on this problem to come up with a
solution I think it is only right to post the solution.

I found that you can't set the soTimeout on an HttpURLConnection as
the sockets are encapsulated within the HttpURLConnection
implementation.

I found Mike Reiche solution in which he uses a handler to set a
timeout value. This nearly worked. Looking at the code in the rt.jar I
found that the initial timeout was working, but the call
parseHTTP(...) in HttpClient was then attempting a second connection
which had a time out value of 0(infinite).

I modified the code to override the doConnect() in the NetworkClient
and managed to get a timeout occurring. To be exact two timeouts
occur.

It works on
java version "1.4.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_03-b04)
Java HotSpot(TM) Client VM (build 1.4.0_03-b04, mixed mode)
and
java version "1.2.2"
Classic VM (build JDK-1.2.2_013, native threads, symcjit)

Anyway here is the code, excuse the formatting.


/* HttpTimeoutURLConnection.java */
import java.net.*;
import java.io.*;
import sun.net.www.http.HttpClient;

// Need to override any function in HttpURLConnection that create a
new HttpClient
// and create a HttpTimeoutClient instead. Those functions are
// connect(), getNewClient(), getProxiedClient()

public class HttpTimeoutURLConnection extends
sun.net.www.protocol.http.HttpURLConnection
{

public HttpTimeoutURLConnection(URL u, HttpTimeoutHandler handler,
int iSoTimeout)
throws IOException
{
super(u, handler);
HttpTimeoutClient.setSoTimeout(iSoTimeout);
}

public void connect() throws IOException
{
if (connected)
{
return;
}

try
{
if ("http".equals(url.getProtocol())) // && !failedOnce <-
PRIVATE
{
// for safety's sake, as reported by KLGroup
synchronized (url)
{
http = HttpTimeoutClient.getNew(url);
}
}
else
{
if (handler instanceof HttpTimeoutHandler)
{
http = new HttpTimeoutClient(super.url,
((HttpTimeoutHandler)handler).getProxy(),
((HttpTimeoutHandler)handler).getProxyPort());
}
else
{
throw new IOException("HttpTimeoutHandler
expected");
}
}

ps = (PrintStream)http.getOutputStream();
}
catch (IOException e)
{
throw e;
}

connected = true;
}


protected HttpClient getNewClient(URL url)
throws IOException
{
HttpTimeoutClient httpTimeoutClient = new HttpTimeoutClient
(url, (String)null, -1);
return httpTimeoutClient;
}


protected HttpClient getProxiedClient(URL url, String s, int i)
throws IOException
{
HttpTimeoutClient httpTimeoutClient = new HttpTimeoutClient
(url, s, i);
return httpTimeoutClient;
}

}


/* HttpTimeoutHandler.java */
import java.net.*;
import java.io.IOException;

public class HttpTimeoutHandler extends
sun.net.www.protocol.http.Handler
{
private int iSoTimeout=0;


public HttpTimeoutHandler(int iSoTimeout)
{
// Divide the time out by two because two connection attempts
are made
// in HttpClient.parseHTTP()

if (iSoTimeout%2!=0)
{
iSoTimeout++;
}
this.iSoTimeout = (iSoTimeout/2);
}

protected java.net.URLConnection openConnection(URL u) throws
IOException
{
return new HttpTimeoutURLConnection(u, this, iSoTimeout);
}

protected String getProxy()
{
return proxy;
}

protected int getProxyPort()
{
return proxyPort;
}
}

/* HttpTimeoutFactory.java */
import java.net.*;

public class HttpTimeoutFactory implements URLStreamHandlerFactory
{
private int iSoTimeout=0;

public HttpTimeoutFactory(int iSoTimeout)
{
this.iSoTimeout = iSoTimeout;
}

public URLStreamHandler createURLStreamHandler(String str)
{
return new HttpTimeoutHandler(iSoTimeout);
}
}


/* HttpTimeoutClient.java */
import sun.net.www.http.HttpClient;
import java.net.*;
import sun.net.*;
import sun.net.www.*;
import java.io.*;

public class HttpTimeoutClient extends HttpClient
{
private static int iSoTimeout=0;

public HttpTimeoutClient(URL url, String proxy, int proxyPort)
throws IOException
{
super(url, proxy, proxyPort);
}

public HttpTimeoutClient(URL url) throws IOException
{
super(url, null, -1);
}

public static HttpTimeoutClient getNew(URL url)
throws IOException
{
HttpTimeoutClient httpTimeoutClient = (HttpTimeoutClient)
kac.get(url);

if (httpTimeoutClient == null)
{
httpTimeoutClient = new HttpTimeoutClient (url); // CTOR
called openServer()
}
else
{
httpTimeoutClient.url = url;
}

return httpTimeoutClient;
}

public static void setSoTimeout(int iNewSoTimeout)
{
iSoTimeout=iNewSoTimeout;
}

public static int getSoTimeout()
{
return iSoTimeout;
}


// Override doConnect in NetworkClient

protected Socket doConnect(String s, int i)
throws IOException, UnknownHostException, SocketException
{
Socket socket=super.doConnect(s,i);

// This is the important bit
socket.setSoTimeout(iSoTimeout);
return socket;
}


}


/* Example use */
import java.util.*;
import java.io.*;
import java.net.*;

public class SystemProperty
{
public static void main(String[] args)
{
String sSoapUrl="http://192.168.0.223/mobaqSecurity/SslTunnelServlet";
System.out.println("Connecting to [" + sSoapUrl + "]");


URLConnection urlConnection = null;
URL url=null;

try
{
url = new URL((URL)null, sSoapUrl, new
HttpTimeoutHandler(10000));
urlConnection = url.openConnection();

// Optional
url.setURLStreamHandlerFactory(new
HttpTimeoutFactory(10000));

System.out.println("Url class
["+urlConnection.getClass().getName()+"]");
}
catch (MalformedURLException mue)
{
System.out.println(">>MalformedURLException<<");
mue.printStackTrace();
}
catch (IOException ioe)
{
System.out.println(">>IOException<<");
ioe.printStackTrace();
}

HttpURLConnection httpConnection =
(HttpURLConnection)urlConnection;
System.out.println("Connected to [" + sSoapUrl + "]");


byte[] messageBytes=new byte[10000];
for (int i=0; i<10000; i++)
{
messageBytes=80;
}

try
{
httpConnection.setRequestProperty("Connection", "Close");
httpConnection.setRequestProperty("Content-Length",
String.valueOf(messageBytes.length));
httpConnection.setRequestProperty("Content-Type",
"text/xml; charset=utf-8");
httpConnection.setRequestMethod("POST");
httpConnection.setDoOutput(true);
httpConnection.setDoInput(true);
}
catch (ProtocolException pe)
{
System.out.println(">>ProtocolException<<");
pe.printStackTrace();
}


OutputStream outputStream=null;

try
{
System.out.println("Getting output stream");
outputStream =httpConnection.getOutputStream();
System.out.println("Got output stream");

outputStream.write(messageBytes);
}
catch (IOException ioe)
{
System.out.println(">>IOException<<");
ioe.printStackTrace();
}


try
{
System.out.println("Getting input stream");
InputStream is=httpConnection.getInputStream();
System.out.println("Got input stream");

byte[] buf = new byte[1000];
int i;

while((i = is.read(buf)) > 0)
{
System.out.println(""+new String(buf));
}
is.close();
}
catch (Exception ie)
{
ie.printStackTrace();
}


}
}


Cheers,
Niels
 
K

ketil v

Niels Campbell skrev:
After spending nearly 3 days on this problem to come up with a
solution I think it is only right to post the solution.

I found that you can't set the soTimeout on an HttpURLConnection as
the sockets are encapsulated within the HttpURLConnection
implementation.

I found Mike Reiche solution in which he uses a handler to set a
timeout value. This nearly worked. Looking at the code in the rt.jar I
found that the initial timeout was working, but the call
parseHTTP(...) in HttpClient was then attempting a second connection
which had a time out value of 0(infinite).

I modified the code to override the doConnect() in the NetworkClient
and managed to get a timeout occurring. To be exact two timeouts
occur.

It works on
java version "1.4.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_03-b04)
Java HotSpot(TM) Client VM (build 1.4.0_03-b04, mixed mode)
and
java version "1.2.2"
Classic VM (build JDK-1.2.2_013, native threads, symcjit)

Anyway here is the code, excuse the formatting.
....
Cheers,
Niels

I've said it since '81: The newsgroups are one of the worlds largest
resources due to the work of fellows like you!

I've struggled with a similar problem a year ago, and am going into it again
in a months time. thank you for the hint, I'll try it.
 
N

Niels Campbell

ketil v said:
Niels Campbell skrev:


I've said it since '81: The newsgroups are one of the worlds largest
resources due to the work of fellows like you!

I've struggled with a similar problem a year ago, and am going into it again
in a months time. thank you for the hint, I'll try it.

I couldn't get the same mechanism to work for (SSL)
HttpsURLConnection. Still managed to come up with a crude solution
which involved tampering with the JVM (not proud of it by any means).
Give me a shout if you need to do SSL.

Cheers,
Niels
 
T

Thomas Scheffler

Niels said:
I couldn't get the same mechanism to work for (SSL)
HttpsURLConnection. Still managed to come up with a crude solution
which involved tampering with the JVM (not proud of it by any means).
Give me a shout if you need to do SSL.

Cheers,
Niels

It would be nice to see a working solution that doesn't need a sun jre
to work, since that problem may exist on other platforms too, where no
sun jre is available...
I have the same problem over here and I'm stuck to the IBM jre...

Thomas Scheffler
 
G

Gabriel Ki

Could you please post it? I would like to see a solution for SSL.

Thanks,
Gabriel
 
Joined
Jul 24, 2006
Messages
1
Reaction score
0
I agree that now 1.6 version is released but still I've to stuck with jdk 1.3 on one of our project. Solution suggested by Niels is good but it can not work in multithreaded environment safely as a static variable is used to set the timeout. Here is the modified solution:

package com.appliancestudio.util;
import sun.net.www.http.HttpClient;
import java.net.*;
import java.io.*;
import com.appliancestudio.utils.Logger;

/**
*
* @author gurmit
*/

public class HttpClientTimeout extends sun.net.www.http.HttpClient {

private int noOfAttempts=0;
private int socketTimeout=0;
public HttpClientTimeout(URL url, String proxy, int proxyPort) throws IOException {
super(url, proxy, proxyPort);
}

public HttpClientTimeout(URL url) throws IOException{
super(url, (String)null, -1);
}

public void SetTimeout(int i) throws SocketException {
noOfAttempts=1;
socketTimeout=i;
serverSocket.setSoTimeout(i);
}

/* This class has no public constructor for HTTP. This method is used to
* get an HttpClient to the specifed URL. If there's currently an
* active HttpClient to that server/port, you'll get that one.
*
* no longer syncrhonized -- it slows things down too much
* synchronize at a higher level
*/
public static HttpClientTimeout GetNew(URL url)
throws IOException {
/* see if one's already around */
HttpClientTimeout ret = (HttpClientTimeout) kac.get(url);
if (ret == null) {
//System.out.println("<HttpClientTimeout> creating object");
ret = new HttpClientTimeout(url); // CTOR called openServer()
} else {
ret.url = url;
}
// don't know if we're keeping alive until we parse the headers
// for now, keepingAlive is false
return ret;
}

public void Close() throws IOException {
serverSocket.close();
}

public Socket GetSocket() {
return serverSocket;
}
/**
* Return a socket connected to the server, with any
* appropriate options pre-established
* I cann't change noOfAttempts here as this method is called from the CTOR of base class
*/
protected Socket doConnect (String server, int port)
throws IOException, UnknownHostException {
//Throw exception if you do not want to attempt second time
if(noOfAttempts!=0){
throw new IOException();
//Or you can try second time as well.
/*Socket soc=super.doConnect(server,port);
soc.setSoTimeout(socketTimeout);
return soc;*/
}
return super.doConnect(server,port);
}

}

Another suggestion: Do not set URLStreamHandlerFactory because if the thread ,which is executing this code, is from a pool then you will get the exception "URLStreamHandlerFactory" is already set, when this code is executed second time.


Regards,
Gurmit
 
Joined
Oct 27, 2006
Messages
1
Reaction score
0
Hi Neil ,

Can you post the code for SSL .

THanks in Advance
Manikandan
Niels Campbell said:
ketil v <[email protected]> wrote in message news:<[email protected]>...
> Niels Campbell skrev:
>
> > After spending nearly 3 days on this problem to come up with a
> > solution I think it is only right to post the solution.
> >
> > I found that you can't set the soTimeout on an HttpURLConnection as
> > the sockets are encapsulated within the HttpURLConnection
> > implementation.
> >
> > I found Mike Reiche solution in which he uses a handler to set a
> > timeout value. This nearly worked. Looking at the code in the rt.jar I
> > found that the initial timeout was working, but the call
> > parseHTTP(...) in HttpClient was then attempting a second connection
> > which had a time out value of 0(infinite).
> >
> > I modified the code to override the doConnect() in the NetworkClient
> > and managed to get a timeout occurring. To be exact two timeouts
> > occur.
> >
> > It works on
> > java version "1.4.0_03"
> > Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_03-b04)
> > Java HotSpot(TM) Client VM (build 1.4.0_03-b04, mixed mode)
> > and
> > java version "1.2.2"
> > Classic VM (build JDK-1.2.2_013, native threads, symcjit)
> >
> > Anyway here is the code, excuse the formatting.
> >

> ...
> > Cheers,
> > Niels

>
> I've said it since '81: The newsgroups are one of the worlds largest
> resources due to the work of fellows like you!
>
> I've struggled with a similar problem a year ago, and am going into it again
> in a months time. thank you for the hint, I'll try it.


I couldn't get the same mechanism to work for (SSL)
HttpsURLConnection. Still managed to come up with a crude solution
which involved tampering with the JVM (not proud of it by any means).
Give me a shout if you need to do SSL.

Cheers,
Niels
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top