I am trying to implement a HTTP Server in Java, I want the server to use a persistent connection per thread for request and response. After some research on Google, this is how my program looks like. It runs fine without any exceptions but I am unable to tell if it is doing what I want it to do, that is connection per thread policy. Can some one please take a look at it and tell me if there any changes to be made or if there are any flaws in my program?
public class TinyHttpd4ServerThread extends Thread{
Socket client;
String line = null;
String httpVersion = null;
boolean connectionKeepAlive;
private ArrayList files = new ArrayList();
ArrayList lineArray = new ArrayList();
ArrayList tokens = new ArrayList();
ArrayList requestHeaderLines;
StringTokenizer st = null;
ReentrantLock lock = new ReentrantLock();
TinyHttpd4ServerThread(Socket socket)
{
this.client = socket;
}
public void run()
{
try
{
lock.lock();
executeCommand(client);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
private void executeCommand( Socket client ){
try {
try {
String fileName = "index.html";
String token = null;
client.setSoTimeout(30000);
BufferedReader in = new BufferedReader( new InputStreamReader( client.getInputStream() ) );
PrintStream out = new PrintStream( client.getOutputStream() );
System.out.println( "I/O setup done" );
String line = in.readLine(); //Get first line of request to check the request command GET or HEAD
StringTokenizer tokenLine = new StringTokenizer(line);
String reqCommand = tokenLine.nextToken();
if (reqCommand.equals("GET") || reqCommand.equals("HEAD")) //only GET or HEAD requests are accepted, else gives 501 error
{
String fname = tokenLine.nextToken();
if(fname.startsWith("/"))
{
while( line != null )
{
// requestHeaderLines.add(line);
System.out.println(line);
if(line.equals("")) break;
StringTokenizer tokenizedLine = new StringTokenizer(line);
while(tokenizedLine.hasMoreTokens())
{
token = tokenizedLine.nextToken();
if(token.endsWith(".html")||token.endsWith(".jpg")) //checking for file types.
files.add(token);
if(token.startsWith("HTTP")) //checking version of the HTTP connection.
if(token.contains("/1.0"))
httpVersion = "HTTP/1.0";
else if(token.contains("/1.1"))
httpVersion = "HTTP/1.1";
if(token.equals("Connection:")) //parsing request to get connection type
if(tokenizedLine.nextToken().equals("keep-alive")) //checking for connection type
connectionKeepAlive = true;
}
line = in.readLine();
}
System.out.println(line);
File file = new File(fileName).getAbsoluteFile();
if(!(file.exists()))
{
out.println("Error Code: 404 \n File not found error...");
}
else
{
System.out.println(file.getName() + " requested.");
System.out.println("Files in this request are: ");
Iterator it = files.iterator();
while(it.hasNext())
{
System.out.println(it.next().toString());
}
sendFile(out, file);
}
}
else
{
out.println("Error Code: 400 \n Bad Request....");
}
}
else
{
out.println("Error code: 501 \n Not Implemented Error....");
}
out.flush();
//out.close();
//in.close();
if(client.isClosed())
System.out.println("client is closed before finally");
}finally {
if(httpVersion.equals("HTTP/1.0") && connectionKeepAlive == false)
{
client.close();
System.out.println( "HTTP/1.0 and Keep-alive = false: Connection is closed." );
}
else if(httpVersion.equals("HTTP/1.0") && connectionKeepAlive == true)
{
client.setKeepAlive(true);
System.out.println("client keep alive: "+client.getKeepAlive());
client.setSoTimeout(5000);
System.out.println("So_timeout set: "+client.getSoTimeout());
}
else if(httpVersion.equals("HTTP/1.1"))
{
client.setKeepAlive(true);
System.out.println("client keep alive: "+client.getKeepAlive());
client.setSoTimeout(5000);
System.out.println("So_timeout set: "+client.getSoTimeout());
}
}
}
catch(SocketTimeoutException e)
{
try {
client.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Socket timeout, Connection closed.");
}
catch(Exception exception) {
exception.printStackTrace();
}
}
private void sendFile(PrintStream out, File file){
try{
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
out.println(httpVersion+" OK");
out.println("Content-Type: text/html");
out.println("Date: "+dateFormat.format(date));
int len = (int) file.length();
out.println("Content-Length: " + len);
out.println("");
DataInputStream fin = new DataInputStream(new FileInputStream(file));
byte buf[] = new byte[len];
fin.readFully(buf);
out.write(buf, 0, len);
out.println("/nFiles in this request are: ");
Iterator it = files.iterator();
while(it.hasNext())
{
out.println(it.next().toString());
}
out.flush();
fin.close();
}catch(IOException exception){
exception.printStackTrace();
}
}
}
The finally clause uses the client.setSoTimeout() and this should throw a timeout exception after 5 sec. I want the connection to be closed when the timeout exception is thrown. but the connection is not closing. the time out exception is not being raised. I cannot understand what is wrong. can some one please tell me what is wrong and how to modify the finally clause such that if the HTTP version is 1.1 or the connection is keep alive then the setSoTimeout should be triggered for say 5 sec and if there is no request or response taking place in these 5 sec then the time out exception should be thrown and the connection should close.