hal/src/zutil/network/http/HttpServer.java

262 lines
8.5 KiB
Java
Raw Normal View History

2008-11-14 16:38:36 +00:00
package zutil.network.http;
import java.io.BufferedReader;
2008-12-03 15:11:04 +00:00
import java.io.File;
2008-11-14 16:38:36 +00:00
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
2009-05-18 12:52:16 +00:00
import java.util.Collections;
2008-11-14 16:38:36 +00:00
import java.util.HashMap;
2009-05-18 12:52:16 +00:00
import java.util.Map;
2009-05-17 18:46:05 +00:00
import java.util.Timer;
import java.util.TimerTask;
2008-12-03 15:11:04 +00:00
2008-11-14 16:38:36 +00:00
import zutil.MultiPrintStream;
import zutil.network.threaded.ThreadedTCPNetworkServer;
import zutil.network.threaded.ThreadedTCPNetworkServerThread;
2008-11-14 16:38:36 +00:00
2009-05-18 12:52:16 +00:00
2008-11-14 16:38:36 +00:00
/**
* A simple web server that handles both cookies and
* sessions for all the clients
*
* @author Ziver
*/
public class HttpServer extends ThreadedTCPNetworkServer{
2008-11-14 16:38:36 +00:00
public static final boolean DEBUG = false;
2009-04-15 19:05:12 +00:00
public static final String SERVER_VERSION = "StaticInt HttpServer 1.0";
2008-11-14 16:38:36 +00:00
public static final int COOKIE_TTL = 200;
2009-05-17 18:46:05 +00:00
public static final int SESSION_TTL = 10*60*1000; // in milliseconds
2008-11-14 16:38:36 +00:00
public final String server_url;
public final int server_port;
private HashMap<String,HttpPage> pages;
private HttpPage defaultPage;
2009-05-18 12:52:16 +00:00
private Map<String,Map<String,Object>> sessions;
2008-11-14 16:38:36 +00:00
private int nextSessionId;
/**
* Creates a new instance of the sever
*
* @param url The address to the server
* @param port The port that the server should listen to
*/
public HttpServer(String url, int port){
2008-12-03 15:11:04 +00:00
this(url, port, null, null);
}
/**
* Creates a new instance of the sever
*
* @param url The address to the server
* @param port The port that the server should listen to
* @param sslCert If this is not null then the server will use SSL connection with this keyStore file path
* @param sslCert If this is not null then the server will use a SSL connection with the given certificate
*/
public HttpServer(String url, int port, File keyStore, String keyStorePass){
super( port, keyStore, keyStorePass );
2008-11-14 16:38:36 +00:00
this.server_url = url;
this.server_port = port;
pages = new HashMap<String,HttpPage>();
2009-05-18 12:52:16 +00:00
sessions = Collections.synchronizedMap(new HashMap<String,Map<String,Object>>());
2008-11-14 16:38:36 +00:00
nextSessionId = 0;
2009-05-17 18:46:05 +00:00
Timer timer = new Timer();
timer.schedule(new GarbageCollector(), 0, SESSION_TTL / 2);
MultiPrintStream.out.println("HTTP"+(keyStore==null?"":"S")+" Server ready!");
2009-05-17 18:46:05 +00:00
}
/**
* This class acts as an garbage collector that
* removes old sessions from the session HashMap
*
* @author Ziver
*/
private class GarbageCollector extends TimerTask {
public void run(){
2009-05-18 12:52:16 +00:00
Object[] keys = sessions.keySet().toArray();
for(Object key : keys){
Map<String,Object> client_session = sessions.get(key);
2009-05-17 18:46:05 +00:00
2009-05-18 12:52:16 +00:00
// Check if session is still valid
if((Long)client_session.get("ttl") < System.currentTimeMillis()){
sessions.remove(key);
if(DEBUG) MultiPrintStream.out.println("Removing Session: "+key);
2009-05-17 18:46:05 +00:00
}
}
2009-05-18 12:52:16 +00:00
2009-05-17 18:46:05 +00:00
}
2008-11-14 16:38:36 +00:00
}
/**
* Add a HttpPage to a specific URL
*
* @param name The URL or name of the page
* @param page The page itself
*/
public void setPage(String name, HttpPage page){
pages.put(name, page);
}
/**
* This is a default page that will be shown
* if there is no other matching page,
*
* @param page The HttpPage that will be shown
*/
public void setDefaultPage(HttpPage page){
defaultPage = page;
}
protected ThreadedTCPNetworkServerThread getThreadInstance( Socket s ){
try {
return new HttpServerThread( s );
} catch (IOException e) {
e.printStackTrace( MultiPrintStream.out );
2008-11-14 16:38:36 +00:00
}
return null;
2008-12-03 15:11:04 +00:00
}
2008-11-14 16:38:36 +00:00
/**
* Internal class that handles all the requests
*
* @author Ziver
*
*/
protected class HttpServerThread implements ThreadedTCPNetworkServerThread{
2008-11-14 16:38:36 +00:00
private HttpPrintStream out;
private BufferedReader in;
private Socket socket;
public HttpServerThread(Socket socket) throws IOException{
out = new HttpPrintStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.socket = socket;
if(DEBUG) MultiPrintStream.out.println("New Connection!!! "+socket.getInetAddress().getHostName());
2008-11-14 16:38:36 +00:00
}
public void run(){
String tmp = null;
String page_url = "";
HashMap<String,String> client_info = new HashMap<String,String>();
HashMap<String,String> cookie = new HashMap<String,String>();
HashMap<String,String> request = new HashMap<String,String>();
//**************************** REQUEST *********************************
try {
if(DEBUG) MultiPrintStream.out.println("Reciving Http Request!!!");
HTTPHeaderParser parser = new HTTPHeaderParser(in);
if(DEBUG) MultiPrintStream.out.println(parser);
client_info = parser.getAttributes();
request = parser.getURLAttributes();
cookie = parser.getCookies();
2008-11-14 16:38:36 +00:00
//******* Read in the post data if available
if( parser.getHTTPAttribute("Content-Length")!=null ){
2008-11-14 16:38:36 +00:00
// Reads the post data size
tmp = parser.getHTTPAttribute("Content-Length");
2009-05-17 18:46:05 +00:00
int post_data_length = Integer.parseInt( tmp );
2009-04-15 19:05:12 +00:00
// read the data
StringBuffer tmpb = new StringBuffer();
// read the data
for(int i=0; i<post_data_length ;i++){
tmpb.append((char)in.read());
}
2008-11-14 16:38:36 +00:00
tmp = parser.getHTTPAttribute("Content-Type");
if( tmp.contains("application/x-www-form-urlencoded") ){
2008-11-14 16:38:36 +00:00
// get the variables
HTTPHeaderParser.parseUrlAttributes( tmpb.toString(), request );
2008-11-14 16:38:36 +00:00
}
else if( tmp.contains("application/soap+xml" ) ||
tmp.contains("text/xml") ||
tmp.contains("text/plain") ){
2009-04-15 19:05:12 +00:00
// save the variables
request.put( "" , tmpb.toString() );
2009-04-15 19:05:12 +00:00
}
else if( tmp.contains("multipart/form-data") ){
2009-05-17 18:46:05 +00:00
// TODO: File upload
throw new Exception( "\"multipart-form-data\" Not implemented!!!" );
2008-11-14 16:38:36 +00:00
}
}
2009-05-17 18:46:05 +00:00
2008-11-14 16:38:36 +00:00
//**************************** HANDLE REQUEST *********************************
// Get the client session or create one
2009-05-18 12:52:16 +00:00
Map<String, Object> client_session;
2009-04-15 19:05:12 +00:00
long ttl_time = System.currentTimeMillis()+SESSION_TTL;
if( cookie.containsKey("session_id") && sessions.containsKey(cookie.get("session_id")) ){
client_session = sessions.get( cookie.get("session_id") );
2009-04-15 19:05:12 +00:00
// Check if session is still valid
if( (Long)client_session.get("ttl") < System.currentTimeMillis() ){
2009-05-17 18:46:05 +00:00
int session_id = (Integer)client_session.get("session_id");
2009-05-18 12:52:16 +00:00
client_session = Collections.synchronizedMap(new HashMap<String, Object>());
client_session.put( "session_id", session_id);
sessions.put( ""+session_id, client_session);
2009-04-15 19:05:12 +00:00
}
// renew the session TTL
client_session.put( "ttl", ttl_time );
2008-11-14 16:38:36 +00:00
}
else{
2009-05-18 12:52:16 +00:00
client_session = Collections.synchronizedMap(new HashMap<String, Object>());
client_session.put( "session_id", nextSessionId );
client_session.put( "ttl", ttl_time );
sessions.put( ""+nextSessionId, client_session );
2008-11-14 16:38:36 +00:00
nextSessionId++;
}
// Debug
if(DEBUG){
MultiPrintStream.out.println( "# page_url: "+page_url );
MultiPrintStream.out.println( "# cookie: "+cookie );
MultiPrintStream.out.println( "# client_session: "+client_session );
MultiPrintStream.out.println( "# client_info: "+client_info );
MultiPrintStream.out.println( "# request: "+request );
2008-11-14 16:38:36 +00:00
}
//**************************** RESPONSE ************************************
if(DEBUG) MultiPrintStream.out.println("Sending Http Response!!!");
2009-05-17 18:46:05 +00:00
out.setStatusCode(200);
out.setHeader( "Server", SERVER_VERSION );
out.setHeader( "Content-Type", "text/html" );
out.setCookie( "session_id", ""+client_session.get("session_id") );
2008-11-14 16:38:36 +00:00
if( !page_url.isEmpty() && pages.containsKey(page_url) ){
2008-11-14 16:38:36 +00:00
pages.get(page_url).respond(out, client_info, client_session, cookie, request);
}
else if( defaultPage != null ){
2008-11-14 16:38:36 +00:00
defaultPage.respond(out, client_info, client_session, cookie, request);
}
else{
out.setStatusCode( 404 );
out.println( "404 Page Not Found" );
2008-11-14 16:38:36 +00:00
}
//********************************************************************************
} catch (Exception e) {
e.printStackTrace( MultiPrintStream.out );
2009-05-17 18:46:05 +00:00
try {
out.setStatusCode( 500 );
2009-05-17 18:46:05 +00:00
} catch (Exception e1) {}
if(e.getMessage() != null)
out.println( "500 Internal Server Error: "+e.getMessage() );
2009-05-17 18:46:05 +00:00
else{
out.println( "500 Internal Server Error: "+e.getCause().getMessage() );
2009-05-17 18:46:05 +00:00
}
2008-11-14 16:38:36 +00:00
}
try{
if(DEBUG) MultiPrintStream.out.println("Conection Closed!!!");
2008-11-14 16:38:36 +00:00
out.close();
in.close();
socket.close();
} catch( Exception e ) {
e.printStackTrace( MultiPrintStream.out );
2009-04-15 19:05:12 +00:00
}
2008-11-14 16:38:36 +00:00
}
}
}