/*
** j###t ########## #### ####
** j###t ########## #### ####
** j###T "###L J###"
** ######P' ########## #########
** ######k, ########## T######T
** ####~###L ####
** #### q###L ########## .#####
** #### \###L ########## #####"
**
** $Id$
**
** Class History
**
** Date Name Description
** ---------|------------|-----------------------------------------------
** 19Aug98 subtle start of recorded history
**
*/
package key;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.util.Vector;
import java.util.StringTokenizer;
/**
* This class is a thread which opens and binds a port,
* creating new instances of 'InteractiveConnectionion' to
* deal with each connection request that comes in.
*/
public class WebConnectPort extends Daemon
{
private static final long serialVersionUID = -3320377023206281762L;
public static final AtomicElement[] ELEMENTS =
{
AtomicElement.construct( WebConnectPort.class, Paragraph.class, "notFound",
AtomicElement.PUBLIC_FIELD,
"the output when the requested URI is not found" ),
AtomicElement.construct( WebConnectPort.class, Paragraph.class, "badRequest",
AtomicElement.PUBLIC_FIELD,
"the output when the URI is badly formatted" ),
AtomicElement.construct( WebConnectPort.class, Paragraph.class, "notImplemented",
AtomicElement.PUBLIC_FIELD,
"the output when the URI is badly formatted" ),
AtomicElement.construct( WebConnectPort.class, Integer.TYPE, "port",
AtomicElement.PUBLIC_FIELD,
"the port number this service binds to" )
};
public static final AtomicStructure STRUCTURE = new AtomicStructure( Daemon.STRUCTURE, ELEMENTS );
// sleep for 5 minutes when we exceed our limit of connections
public static final int SLEEP_DURATION = 5 * 60 * 1000;
protected Paragraph notFound = new TextParagraph( "<HTML><HEAD><TITLE>Object not found</TITLE></HEAD><BODY><CENTER><B>The object you requested does not exist or is not accessible via the web</B></CENTER></BODY></HTML>" );
protected Paragraph badRequest = new TextParagraph( "<HTML><HEAD><TITLE>Bad Request</TITLE></HEAD><BODY><CENTER><B>Invalid URL</B></CENTER></BODY></HTML>" );
protected Paragraph notImplemented = new TextParagraph( "<HTML><HEAD><TITLE>Method not implemented</TITLE></HEAD><BODY><CENTER><B>Unknown method</B></CENTER></BODY></HTML>" );
public int port;
private transient ServerSocket socket = null;
public WebConnectPort()
{
}
public WebConnectPort( int portNumber )
{
port = portNumber;
}
public WebConnectPort( Object key, int portNumber )
{
port = portNumber;
setKey( key );
}
public AtomicStructure getDeclaredStructure()
{
return( STRUCTURE );
}
public void argument( String args )
{
if( args.length() > 0 )
{
try
{
port = Integer.parseInt( args );
}
catch( NumberFormatException e )
{
throw new IllegalArgumentException( "'" + args + "' is not an integer port number" );
}
}
}
public void run()
{
try
{
serveRequests();
}
catch( Throwable t )
{
if( t instanceof ThreadDeath )
throw (ThreadDeath) t;
else
Log.fatal( this, t.toString() );
}
}
private static final String CONNECTION_LOG = "www_conn";
private void serveRequests()
{
try
{
socket = new ServerSocket( port );
}
catch( java.io.IOException e )
{
Log.log( CONNECTION_LOG, e.toString() );
stop();
return;
}
InetAddress ourAddress = socket.getInetAddress();
String hn = ourAddress.getHostName();
Log.log( CONNECTION_LOG, "'" + hn + " " + port + "' initialised" );
WebConnection tc = null;
Socket thisConnection = null;
try
{
while( true )
{
try
{
thisConnection = socket.accept();
}
catch( java.net.SocketException e )
{
// this almost certainly means we've been killed
socket.close();
break;
}
try
{
tc = new WebConnection( thisConnection, this );
}
catch( IOException e )
{
continue;
}
catch( LimitExceededException e )
{
// generally means we've exceeded our
// limit of sockets, or something
// really funny has happened
try
{
Thread.sleep( SLEEP_DURATION );
}
catch( InterruptedException ex )
{
}
continue;
}
Site site = tc.getSite();
if( !site.connectionsAllowed() )
{
// META: change this
handleSiteban( tc );
tc.close();
}
else
{
tc.start();
}
// clean up our references so that they
// can be garbage collected
tc = null;
thisConnection = null;
yield();
}
}
catch( Exception e )
{
if( Key.isRunning() )
{
Log.debug( this, e.toString() + " during scan" );
e.printStackTrace( System.out );
}
}
}
public void handleSiteban( WebConnection wc )
{
}
public void handleConnection( WebConnection wc )
{
try
{
String line = wc.input();
StringTokenizer st = new StringTokenizer( line );
if( st.hasMoreTokens() )
{
String cmd = st.nextToken();
if( cmd.equalsIgnoreCase( "get" ) )
{
if( st.hasMoreTokens() )
{
String where = st.nextToken();
String proto = null;
if( st.hasMoreTokens() )
{
proto = st.nextToken();
System.err.println( "WC rc: " + line );
if( proto.startsWith( "HTTP/" ) )
{
String nextLine;
do
{
nextLine = wc.input();
System.err.println( "WC rc: " + nextLine );
} while( nextLine.length() > 0 );
}
}
try
{
Object o = new Search( where, Key.instance() ).result;
if( o instanceof WebAccessible )
{
printHeaders( wc, "200 OK" );
WebAccessible wa = (WebAccessible) o;
wc.println( "Content-type: " + wa.getContentType() );
wc.println( "" );
wc.send( wa.getContent( st.hasMoreTokens() ? st.nextToken( "" ) : "" ) );
}
else if( o instanceof Paragraph )
{
printHeaders( wc, "200 OK" );
wc.println( "Content-type: text/html" );
wc.println( "" );
wc.send( (Paragraph) o );
}
else
{
printHeaders( wc, "404 Object Not Found" );
wc.println( "Content-type: text/html" );
wc.println( "" );
wc.send( notFound );
}
}
catch( InvalidSearchException e )
{
printHeaders( wc, "404 Object Not Found" );
wc.println( "Content-type: text/html" );
wc.println( "" );
wc.send( notFound );
}
}
else
{
printHeaders( wc, "400 No arguments" );
wc.println( "Content-type: text/html" );
wc.println( "" );
wc.send( badRequest );
}
}
else
{
printHeaders( wc, "501 Not implemented" );
wc.println( "Content-type: text/html" );
wc.println( "" );
wc.send( notImplemented );
}
}
else
{
printHeaders( wc, "400 Bad Request " );
wc.println( "Content-type: text/html" );
wc.println( "" );
wc.send( badRequest );
}
}
catch( Exception e )
{
System.err.println( e.toString() );
}
finally
{
try
{
wc.flush();
wc.close();
}
catch( Exception ex )
{
}
wc.stop();
}
}
public void printHeaders( WebConnection wc, String result ) throws IOException
{
wc.println( "HTTP/1.0 " + result );
wc.println( "Server: Key" );
wc.println( "Date: " + (new Date()).toString() );
}
}