dcsimg
SocketTimeout while waiting for HTTP response
0 posts in topic
Flat View  Flat View
TOPIC ACTIONS:
 

Posted By:   Jeroen_Sikking
Posted On:   Thursday, January 17, 2008 07:39 AM

Hi, An application I'm working on uses a custom HTTP class which handles HTTP requests to external websites and allows me to manipulate headers, cookies and response data in a way that I haven't been able to do with the HTTP classes in the standard API. This works quite well in most cases. But once in a while the remote HTTP server accepts my request and just sites there, not responding to the request, eventually resulting in a SocketTimeout exception. About 9 times out of 10 it seems to help if I send an extra empty line after the request. But it still doesn't work all the time. The SocketTimeout always occurs in the readStatusLine function. Whe   More>>

Hi,


An application I'm working on uses a custom HTTP class which handles HTTP requests to external websites and allows me to manipulate headers, cookies and response data in a way that I haven't been able to do with the HTTP classes in the standard API.



This works quite well in most cases. But once in a while the remote HTTP server accepts my request and just sites there, not responding to the request, eventually resulting in a SocketTimeout exception.



About 9 times out of 10 it seems to help if I send an extra empty line after the request. But it still doesn't work all the time.



The SocketTimeout always occurs in the readStatusLine function.



When I do the same request from a browser or manually using telnet, the remote server responds perfectly. This happens with multiple remote servers of different types (Apache, IIS etc) belonging to different companies so the problem is definitely on my side.



Does anyone have an idea what I might be doing wrong?


			

public void performRequest() throws IOException {

String queryData = "";

if (method.equals("get")) {
if (!requestParameters.isEmpty()) {
queryData = compileQueryData();
} else {
queryData = urlObject.getQuery();
}
} else if (method.equals("post")) {
queryData = compileQueryData();

addRequestHeader("Content-type", "application/x-www-form-urlencoded");
addRequestHeader("Content-length", "" + queryData.length());
}

System.out.println("Connecting to host " + host + " and port: " + port);

// The SOCKET_TIMEOUT is set to 10000 ms
Socket socket = new Socket(host, port);
socket.setSoTimeout(SOCKET_TIMEOUT);

System.out.println("Connected to host " + host + " and port: " + port);

try {
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();

String requestLine = method.toUpperCase();
requestLine += " " + path;

if (queryData != null && method.equals("get")) {
requestLine += "?" + queryData;
}

requestLine += " HTTP/1.1";

sendLine(os, requestLine);
sendLine(os, "Host: " + host);
sendCookies(os);

if (referer != null) {
sendLine(os, "Referer: " + referer);
}

sendRequestHeaders(os);

sendLine(os, "");

if (method.equals("post")) {
printDebugLine(queryData);
os.write(queryData.getBytes());
}

os.flush();

readStatusLine(is, os);

String header = readHeader(is);
while (!header.equals("")) {
header = readHeader(is);
}

StringBuffer resultBuffer = new StringBuffer("");

if (responseStatus != 302) {
if (responseIsChunked) {
printDebugLine("Response is chunked");
int chunkSize = readNextChunkSize(is);

while (chunkSize != 0) {
String chunk = readNextChunk(is, chunkSize);
resultBuffer.append(chunk);
chunkSize = readNextChunkSize(is);
}
} else {
printDebugLine("Response is not chunked");

if (responseHeaders.get("content-length") != null) {
int contentLength = new Integer((String) responseHeaders.get("content-length")).intValue();
byte[] buffer = new byte[contentLength];

int position = 0;
int readCount = 0;

do {
int maxReadCount = 10240;
if (position + maxReadCount > contentLength) maxReadCount = contentLength - position;

readCount = is.read(buffer, position, maxReadCount);

position += readCount;

} while (readCount != -1 && position < contentLength);

resultBytes = buffer;
resultBuffer = new StringBuffer(new String(buffer));
} else if (expectBinary) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();

int b = is.read();

while (b != -1) {
bos.write(b);
b = is.read();
}

resultBytes = bos.toByteArray();

} else {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = br.readLine();

while (line != null && line.toLowerCase().indexOf(" ") == -1) {
resultBuffer.append(line + "
");
line = br.readLine();
}
}
}
}

socket.close();

result = resultBuffer.toString();
printDebugLine("Result: " + result);
} catch (IOException e) {
socket.close();
throw e;
} catch (Exception e) {
socket.close();
}
}

private void sendLine(OutputStream os, String line) throws IOException {
printDebugLine(line);
line = line + "
";
os.write(line.getBytes());
}

private String getCookieValues() {

String cookieValues = "";

Vector cookies = loginSession.getCookiesForHost(host);

for (Enumeration enu = cookies.elements(); enu.hasMoreElements();) {

DomainCookie cookie = (DomainCookie) enu.nextElement();
String cookiedomain = cookie.getDomain();

if (host.indexOf(cookiedomain) != -1) {
String name = cookie.getName();
String value = cookie.getValue();

cookieValues += name + "=" + value + ";";
}
}

return cookieValues;
}

private void sendRequestHeaders(OutputStream os) throws IOException {
for (Enumeration enu = requestHeaders.keys(); enu.hasMoreElements();) {
String name = (String) enu.nextElement();
String value = (String) requestHeaders.get(name);

sendLine(os, name + ": " + value);
}

}

private void readStatusLine(InputStream is, OutputStream os) throws IOException {
printDebugLine("Reading status line...");
StringWriter sw = new StringWriter();


int b = -1;

try {
b = is.read();
} catch (SocketTimeoutException e) {
printDebugLine("Got socket timeout. Trying to send an extra empty line...");
sendLine(os, "");
os.flush();

try {
b = is.read();
} catch (SocketTimeoutException e2) {
printDebugLine("No effect... I give up");
throw e2;
}
}

while (b != '
') {
sw.write(b);
b = is.read();
}

String statusLine = sw.toString();
printDebugLine(statusLine);

StringTokenizer st = new StringTokenizer(statusLine, " ", false);
st.nextToken();

responseStatus = -1;

try {
responseStatus = Integer.parseInt(st.nextToken());
} catch (NumberFormatException e) {
System.err.println("Number format exception while parsing response status. Ignoring.");
}
}

private String readHeader(InputStream is) throws IOException {
StringWriter sw = new StringWriter();

int b = is.read();
while (b != '
') {
sw.write(b);
b = is.read();
}

String header = sw.toString().trim();
printDebugLine(header);

if (header.indexOf(':') != -1) {
String name = header.substring(0, header.indexOf(":")).toLowerCase();
String value = header.substring(header.indexOf(":") + 1).trim();

responseHeaders.put(name, value);

if (name.equals("set-cookie")) {
setCookie(host, value);
} else if (value.trim().equals("chunked")) {
responseIsChunked = true;
}
}

return header;
}


I'm running this code in an application deployed in JBoss 4.0.2 / jdk 1.5.0_06 on an Fedora Core 4 system.



It's starting to look like it has something to do with how busy the system is. The more sockets are opened, the more often the timeout occurs.



When I run netstat, it doesn't show a huge number of open sockets though.

   <<Less
About | Sitemap | Contact