@ -40,37 +40,37 @@
/ *
/ *
Class documentation :
Class documentation :
this class provides a file servlet and CGI interface
this class provides a file servlet and CGI interface
for the httpd server .
for the httpd server .
Whenever this server is addressed to load a local file ,
Whenever this server is addressed to load a local file ,
this class searches for the file in the local path as
this class searches for the file in the local path as
configured in the setting property ' rootPath '
configured in the setting property ' rootPath '
The servlet loads the file and returns it to the client .
The servlet loads the file and returns it to the client .
Every file can also act as an template for the built - in
Every file can also act as an template for the built - in
CGI interface . There is no specific path for CGI functions .
CGI interface . There is no specific path for CGI functions .
CGI functionality is triggered , if for the file to - be - served
CGI functionality is triggered , if for the file to - be - served
' template . html ' also a file ' template . class ' exists . Then ,
' template . html ' also a file ' template . class ' exists . Then ,
the class file is called with the GET / POST properties that
the class file is called with the GET / POST properties that
are attached to the http call .
are attached to the http call .
Possible variable hand - over are :
Possible variable hand - over are :
- form method GET
- form method GET
- form method POST , enctype text / plain
- form method POST , enctype text / plain
- form method POST , enctype multipart / form - data
- form method POST , enctype multipart / form - data
The class that creates the CGI respond must have at least one
The class that creates the CGI respond must have at least one
static method of the form
static method of the form
public static java . util . Hashtable respond ( java . util . HashMap , serverSwitch )
public static java . util . Hashtable respond ( java . util . HashMap , serverSwitch )
In the HashMap , the GET / POST variables are handed over .
In the HashMap , the GET / POST variables are handed over .
The return value is a Property object that contains replacement
The return value is a Property object that contains replacement
key / value pairs for the patterns in the template file .
key / value pairs for the patterns in the template file .
The templates must have the form
The templates must have the form
either ' # [ ' < name > ' ] # ' for single attributes , or
either ' # [ ' < name > ' ] # ' for single attributes , or
' # { ' < enumname > ' } # ' and ' # { / ' < enumname > ' } # ' for enumerations of
' # { ' < enumname > ' } # ' and ' # { / ' < enumname > ' } # ' for enumerations of
values ' # [ ' < value > ' ] # ' .
values ' # [ ' < value > ' ] # ' .
A single value in repetitions / enumerations in the template has
A single value in repetitions / enumerations in the template has
the property key '_' < enumname > < count > '_' < value >
the property key '_' < enumname > < count > '_' < value >
Please see also the example files ' test . html ' and ' test . java '
Please see also the example files ' test . html ' and ' test . java '
* /
* /
package de.anomic.http ;
package de.anomic.http ;
@ -83,24 +83,29 @@ import java.io.OutputStream;
import java.io.PushbackInputStream ;
import java.io.PushbackInputStream ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
import java.lang.reflect.Method ;
import java.security.MessageDigest ;
import java.security.NoSuchAlgorithmException ;
import java.util.Date ;
import java.util.Date ;
import java.util.Enumeration ;
import java.util.Enumeration ;
import java.util.HashMap ;
import java.util.HashMap ;
import java.util.Iterator ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Map ;
import java.util.Properties ;
import java.util.Properties ;
import java.util.zip.GZIPOutputStream ;
import sun.security.provider.MD5 ;
import de.anomic.server.serverByteBuffer ;
import de.anomic.server.serverByteBuffer ;
import de.anomic.server.serverClassLoader ;
import de.anomic.server.serverClassLoader ;
import de.anomic.server.serverCodings ;
import de.anomic.server.serverCodings ;
import de.anomic.server.serverCore ;
import de.anomic.server.serverCore ;
import de.anomic.server.serverFileUtils ;
import de.anomic.server.serverFileUtils ;
import de.anomic.server.serverLog ;
import de.anomic.server.serverObjects ;
import de.anomic.server.serverObjects ;
import de.anomic.server.serverSwitch ;
import de.anomic.server.serverSwitch ;
import de.anomic.server.logging.serverLog ;
public final class httpdFileHandler extends httpdAbstractHandler implements httpdHandler {
public final class httpdFileHandler extends httpdAbstractHandler implements httpdHandler {
// class variables
// class variables
private Properties mimeTable = null ;
private Properties mimeTable = null ;
private serverClassLoader provider = null ;
private serverClassLoader provider = null ;
@ -111,181 +116,177 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http
private String [ ] defaultFiles = null ;
private String [ ] defaultFiles = null ;
private File htDefaultPath = null ;
private File htDefaultPath = null ;
private File htLocalePath = null ;
private File htLocalePath = null ;
private serverSwitch switchboard ;
private serverSwitch switchboard ;
private String adminAccountBase64MD5 ;
private String adminAccountBase64MD5 ;
private Properties connectionProperties = null ;
private MessageDigest md5Digest = null ;
public httpdFileHandler ( serverSwitch switchboard ) {
public httpdFileHandler ( serverSwitch switchboard ) {
this . switchboard = switchboard ;
this . switchboard = switchboard ;
if ( this . mimeTable = = null ) {
// load the mime table
this . mimeTable = new Properties ( ) ;
String mimeTablePath = switchboard . getConfig ( "mimeConfig" , "" ) ;
FileInputStream mimeTableInputStream = null ;
try {
serverLog . logSystem ( "HTTPDFiles" , "Loading mime mapping file " + mimeTablePath ) ;
mimeTableInputStream = new FileInputStream ( new File ( switchboard . getRootPath ( ) , mimeTablePath ) ) ;
this . mimeTable . load ( mimeTableInputStream ) ;
} catch ( Exception e ) {
if ( mimeTableInputStream ! = null ) try { mimeTableInputStream . close ( ) ; } catch ( Exception e1 ) { }
serverLog . logError ( "HTTPDFiles" , "ERROR: path to configuration file or configuration invalid\n" + e ) ;
System . exit ( 1 ) ;
}
}
// create default files array
if ( this . mimeTable = = null ) {
defaultFiles = switchboard . getConfig ( "defaultFiles" , "index.html" ) . split ( "," ) ;
// load the mime table
if ( defaultFiles . length = = 0 ) defaultFiles = new String [ ] { "index.html" } ;
this . mimeTable = new Properties ( ) ;
String mimeTablePath = switchboard . getConfig ( "mimeConfig" , "" ) ;
FileInputStream mimeTableInputStream = null ;
try {
serverLog . logSystem ( "HTTPDFiles" , "Loading mime mapping file " + mimeTablePath ) ;
mimeTableInputStream = new FileInputStream ( new File ( switchboard . getRootPath ( ) , mimeTablePath ) ) ;
this . mimeTable . load ( mimeTableInputStream ) ;
} catch ( Exception e ) {
if ( mimeTableInputStream ! = null ) try { mimeTableInputStream . close ( ) ; } catch ( Exception e1 ) { }
serverLog . logError ( "HTTPDFiles" , "ERROR: path to configuration file or configuration invalid\n" + e ) ;
System . exit ( 1 ) ;
}
}
// create a htRootPath: system pages
// create default files array
if ( htRootPath = = null ) {
defaultFiles = switchboard . getConfig ( "defaultFiles" , "index.html" ) . split ( "," ) ;
htRootPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htRootPath" , "htroot" ) ) ;
if ( defaultFiles . length = = 0 ) defaultFiles = new String [ ] { "index.html" } ;
if ( ! ( htRootPath . exists ( ) ) ) htRootPath . mkdir ( ) ;
}
// create a htDocsPath: user defined pages
// create a htRootPath: system pages
if ( htDocsPath = = null ) {
if ( htRootPath = = null ) {
htDocsPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htDocsPath" , "htdocs" ) ) ;
htRootPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htRootPath" , "htroot" ) ) ;
if ( ! ( htDocsPath . exists ( ) ) ) htDocsPath . mkdir ( ) ;
if ( ! ( htRootPath . exists ( ) ) ) htRootPath . mkdir ( ) ;
}
}
// create a htTemplatePath
// create a htDocsPath: user defined pages
if ( htTemplatePath = = null ) {
if ( htDocsPath = = null ) {
htTemplatePath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htTemplatePath" , "htroot/env/templates" ) ) ;
htDocsPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htDocsPath" , "htdocs" ) ) ;
if ( ! ( htTemplatePath . exists ( ) ) ) htTemplatePath . mkdir ( ) ;
if ( ! ( htDocsPath . exists ( ) ) ) htDocsPath . mkdir ( ) ;
}
}
// create a htTemplatePath
if ( htTemplatePath = = null ) {
htTemplatePath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htTemplatePath" , "htroot/env/templates" ) ) ;
if ( ! ( htTemplatePath . exists ( ) ) ) htTemplatePath . mkdir ( ) ;
}
if ( templates = = null ) templates = loadTemplates ( htTemplatePath ) ;
if ( templates = = null ) templates = loadTemplates ( htTemplatePath ) ;
// create htLocaleDefault, htLocalePath
if ( htDefaultPath = = null ) htDefaultPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htDefaultPath" , "htroot" ) ) ;
if ( htLocalePath = = null ) htLocalePath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htLocalePath" , "htroot/locale" ) ) ;
//htLocaleSelection = switchboard.getConfig("htLocaleSelection","default");
// create a class loader
if ( provider = = null ) {
provider = new serverClassLoader ( /*this.getClass().getClassLoader()*/ ) ;
// debug
/ *
Package [ ] ps = ( ( cachedClassLoader ) provider ) . packages ( ) ;
for ( int i = 0 ; i < ps . length ; i + + ) System . out . println ( "PACKAGE IN PROVIDER: " + ps [ i ] . toString ( ) ) ;
* /
}
adminAccountBase64MD5 = null ;
serverLog . logSystem ( "HTTPDFileHandler" , "File Handler Initialized" ) ;
// create htLocaleDefault, htLocalePath
}
if ( htDefaultPath = = null ) htDefaultPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htDefaultPath" , "htroot" ) ) ;
if ( htLocalePath = = null ) htLocalePath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( "htLocalePath" , "htroot/locale" ) ) ;
private void respondHeader ( OutputStream out , int retcode ,
//htLocaleSelection = switchboard.getConfig("htLocaleSelection","default");
String conttype , long contlength ,
Date moddate , Date expires ,
// create a class loader
String cookie ) throws IOException {
if ( provider = = null ) {
try {
provider = new serverClassLoader ( /*this.getClass().getClassLoader()*/ ) ;
out . write ( ( "HTTP/1.1 " + retcode + " OK\r\n" ) . getBytes ( ) ) ;
// debug
out . write ( ( httpHeader . SERVER + ": AnomicHTTPD (www.anomic.de)\r\n" ) . getBytes ( ) ) ;
/ *
out . write ( ( httpHeader . DATE + ": " + httpc . dateString ( httpc . nowDate ( ) ) + "\r\n" ) . getBytes ( ) ) ;
Package [ ] ps = ( ( cachedClassLoader ) provider ) . packages ( ) ;
if ( expires ! = null ) out . write ( ( "Expires: " + httpc . dateString ( expires ) + "\r\n" ) . getBytes ( ) ) ;
for ( int i = 0 ; i < ps . length ; i + + ) System . out . println ( "PACKAGE IN PROVIDER: " + ps [ i ] . toString ( ) ) ;
out . write ( ( httpHeader . CONTENT_TYPE + ": " + conttype /* "image/gif", "text/html" */ + "\r\n" ) . getBytes ( ) ) ;
* /
out . write ( ( httpHeader . LAST_MODIFIED + ": " + httpc . dateString ( moddate ) + "\r\n" ) . getBytes ( ) ) ;
}
out . write ( ( httpHeader . CONTENT_LENGTH + ": " + contlength + "\r\n" ) . getBytes ( ) ) ;
adminAccountBase64MD5 = null ;
out . write ( ( httpHeader . PRAGMA + ": no-cache\r\n" ) . getBytes ( ) ) ;
// out.write(("Accept-ranges: bytes\r\n").getBytes());
// initialise an message digest for Content-MD5 support ...
if ( cookie ! = null ) out . write ( ( httpHeader . SET_COOKIE + ": " + cookie + "\r\n" ) . getBytes ( ) ) ;
try {
out . write ( ( "\r\n" ) . getBytes ( ) ) ;
this . md5Digest = MessageDigest . getInstance ( "MD5" ) ;
out . flush ( ) ;
} catch ( NoSuchAlgorithmException e ) {
} catch ( Exception e ) {
serverLog . logWarning ( "HTTPDFileHandler" , "Content-MD5 support not availabel ..." ) ;
// any interruption may be caused be network error or because the user has closed
}
// the windows during transmission. We simply pass it as IOException
throw new IOException ( e . getMessage ( ) ) ;
serverLog . logSystem ( "HTTPDFileHandler" , "File Handler Initialized" ) ;
}
}
}
private void textMessage ( OutputStream out , int retcode , String body ) throws IOException {
// private void textMessage(OutputStream out, int retcode, String body) throws IOException {
respondHeader ( out , retcode , "text/plain" , body . length ( ) , httpc . nowDate ( ) , null , null ) ;
// httpd.sendRespondHeader(
out . write ( body . getBytes ( ) ) ;
// this.connectionProperties, // the connection properties
out . flush ( ) ;
// out, // the output stream
// "HTTP/1.1", // the http version that should be used
// retcode, // the http status code
// null, // the http status message
// "text/plain", // the mimetype
// body.length(), // the content length
// httpc.nowDate(), // the modification date
// null, // the expires date
// null, // cookies
// null, // content encoding
// null); // transfer encoding
// out.write(body.getBytes());
// out.flush();
// }
private httpHeader getDefaultHeaders ( ) {
httpHeader headers = new httpHeader ( ) ;
headers . put ( httpHeader . SERVER , "AnomicHTTPD (www.anomic.de)" ) ;
headers . put ( httpHeader . DATE , httpc . dateString ( httpc . nowDate ( ) ) ) ;
headers . put ( httpHeader . PRAGMA , "no-cache" ) ;
return headers ;
}
}
public void doGet ( Properties conProp , httpHeader requestHeader , OutputStream response ) throws IOException {
public void doGet ( Properties conProp , httpHeader requestHeader , OutputStream response ) throws IOException {
doResponse ( conProp , requestHeader , response , null ) ;
doResponse ( conProp , requestHeader , response , null ) ;
}
}
public void doHead ( Properties conProp , httpHeader requestHeader , OutputStream response ) throws IOException {
public void doHead ( Properties conProp , httpHeader requestHeader , OutputStream response ) throws IOException {
doResponse ( conProp , requestHeader , response , null ) ;
doResponse ( conProp , requestHeader , response , null ) ;
}
}
public void doPost ( Properties conProp , httpHeader requestHeader , OutputStream response , PushbackInputStream body ) throws IOException {
public void doPost ( Properties conProp , httpHeader requestHeader , OutputStream response , PushbackInputStream body ) throws IOException {
doResponse ( conProp , requestHeader , response , body ) ;
doResponse ( conProp , requestHeader , response , body ) ;
}
}
public void doResponse ( Properties conProp , httpHeader requestHeader , OutputStream out , PushbackInputStream body ) throws IOException {
public void doResponse ( Properties conProp , httpHeader requestHeader , OutputStream out , PushbackInputStream body ) throws IOException {
String userAgent = ( String ) requestHeader . get ( httpHeader . USER_AGENT ) ;
this . connectionProperties = conProp ;
if ( userAgent = = null ) userAgent = "" ;
userAgent = userAgent . trim ( ) . toLowerCase ( ) ;
// getting some connection properties
//userAgent = "portalmmm n400i"; // debug
String method = conProp . getProperty ( httpd . CONNECTION_PROP_METHOD ) ;
//boolean iMode = (userAgent.startsWith("portalmmm"));
String path = conProp . getProperty ( httpd . CONNECTION_PROP_PATH ) ;
//if (iMode) System.out.println("DETECTED IMODE");
String argsString = conProp . getProperty ( httpd . CONNECTION_PROP_ARGS ) ; // is null if no args were given
String httpVersion = conProp . getProperty ( httpd . CONNECTION_PROP_HTTP_VER ) ;
//System.out.println("HTTPD-REQUEST FROM CLIENT: " + userAgent); // DEBUG
String url = "http://" + requestHeader . get ( httpHeader . HOST , "localhost" ) + path ;
// prepare response
// check hack attacks in path
String method = conProp . getProperty ( "METHOD" ) ;
if ( path . indexOf ( ".." ) > = 0 ) {
String path = conProp . getProperty ( "PATH" ) ;
httpd . sendRespondHeader ( conProp , out , httpVersion , 403 , getDefaultHeaders ( ) ) ;
String argsString = conProp . getProperty ( "ARGS" ) ; // is null if no args were given
return ;
}
// check hack attacks in path
if ( path . indexOf ( ".." ) > = 0 ) {
out . write ( ( "HTTP/1.0 403 bad path\r\n" ) . getBytes ( ) ) ;
out . write ( ( "\r\n" ) . getBytes ( ) ) ;
out . flush ( ) ;
return ;
}
// check permission/granted access
// check permission/granted access
if ( ( path . endsWith ( "_p.html" ) ) & &
if ( ( path . endsWith ( "_p.html" ) ) & &
( ( adminAccountBase64MD5 = switchboard . getConfig ( "adminAccountBase64MD5" , "" ) ) . length ( ) ! = 0 ) ) {
( ( adminAccountBase64MD5 = switchboard . getConfig ( "adminAccountBase64MD5" , "" ) ) . length ( ) ! = 0 ) ) {
// authentication required
// authentication required
String auth = ( String ) requestHeader . get ( httpHeader . AUTHORIZATION ) ;
String auth = ( String ) requestHeader . get ( httpHeader . AUTHORIZATION ) ;
if ( auth = = null ) {
if ( auth = = null ) {
// no authorization given in response. Ask for that
// no authorization given in response. Ask for that
out . write ( ( "HTTP/1.1 401 log-in required\r\n" ) . getBytes ( ) ) ;
httpHeader headers = getDefaultHeaders ( ) ;
out . write ( ( httpHeader . WWW_AUTHENTICATE + ": Basic realm=\"admin log-in\"\r\n" ) . getBytes ( ) ) ;
headers . put ( httpHeader . WWW_AUTHENTICATE , "Basic realm=\"admin log-in\"" ) ;
out . write ( ( "\r\n" ) . getBytes ( ) ) ;
httpd . sendRespondHeader ( conProp , out , httpVersion , 401 , headers ) ;
out . flush ( ) ;
return ;
return ;
} else if ( adminAccountBase64MD5 . equals ( serverCodings . standardCoder . encodeMD5Hex ( auth . trim ( ) . substring ( 6 ) ) ) ) {
} else if ( adminAccountBase64MD5 . equals ( serverCodings . standardCoder . encodeMD5Hex ( auth . trim ( ) . substring ( 6 ) ) ) ) {
// remove brute-force flag
// remove brute-force flag
serverCore . bfHost . remove ( conProp . getProperty ( "CLIENTIP" ) ) ;
serverCore . bfHost . remove ( conProp . getProperty ( "CLIENTIP" ) ) ;
} else {
} else {
// a wrong authentication was given. Ask again
// a wrong authentication was given. Ask again
String clientIP = conProp . getProperty ( "CLIENTIP" , "unknown-host" ) ;
String clientIP = conProp . getProperty ( "CLIENTIP" , "unknown-host" ) ;
serverLog . logInfo ( "HTTPD" , "Wrong log-in for account 'admin' in http file handler for path '" + path + "' from host '" + clientIP + "'" ) ;
serverLog . logInfo ( "HTTPD" , "Wrong log-in for account 'admin' in http file handler for path '" + path + "' from host '" + clientIP + "'" ) ;
//try {Thread.currentThread().sleep(3000);} catch (InterruptedException e) {} // add a delay to make brute-force harder
serverCore . bfHost . put ( clientIP , "sleep" ) ;
serverCore . bfHost . put ( clientIP , "sleep" ) ;
out . write ( ( "HTTP/1.1 401 log-in required\r\n" ) . getBytes ( ) ) ;
httpHeader headers = getDefaultHeaders ( ) ;
out . write ( ( httpHeader . WWW_AUTHENTICATE + ": Basic realm=\"admin log-in\"\r\n" ) . getBytes ( ) ) ;
headers . put ( httpHeader . WWW_AUTHENTICATE , "Basic realm=\"admin log-in\"" ) ;
out . write ( ( "\r\n" ) . getBytes ( ) ) ;
httpd . sendRespondHeader ( conProp , out , httpVersion , 401 , headers ) ;
out . flush ( ) ;
//System.out.println("httpd bfHosts=" + serverCore.bfHost.toString());
return ;
return ;
}
}
}
}
// parse arguments
// parse arguments
serverObjects args = new serverObjects ( ) ;
serverObjects args = new serverObjects ( ) ;
int argc ;
int argc ;
if ( argsString = = null ) {
if ( argsString = = null ) {
// no args here, maybe a POST with multipart extension
// no args here, maybe a POST with multipart extension
int length ;
int length ;
//System.out.println("HEADER: " + requestHeader.toString()); // DEBUG
//System.out.println("HEADER: " + requestHeader.toString()); // DEBUG
if ( ( method . equals ( httpHeader . METHOD_POST ) ) & &
if ( ( method . equals ( httpHeader . METHOD_POST ) ) & &
( requestHeader . containsKey ( httpHeader . CONTENT_LENGTH ) ) ) {
( requestHeader . containsKey ( httpHeader . CONTENT_LENGTH ) ) ) {
// if its a POST, it can be either multipart or as args in the body
// if its a POST, it can be either multipart or as args in the body
length = Integer . parseInt ( ( String ) requestHeader . get ( httpHeader . CONTENT_LENGTH ) ) ;
length = Integer . parseInt ( ( String ) requestHeader . get ( httpHeader . CONTENT_LENGTH ) ) ;
if ( ( requestHeader . containsKey ( httpHeader . CONTENT_TYPE ) ) & &
if ( ( requestHeader . containsKey ( httpHeader . CONTENT_TYPE ) ) & &
( ( ( String ) requestHeader . get ( httpHeader . CONTENT_TYPE ) ) . toLowerCase ( ) . startsWith ( "multipart" ) ) ) {
( ( ( String ) requestHeader . get ( httpHeader . CONTENT_TYPE ) ) . toLowerCase ( ) . startsWith ( "multipart" ) ) ) {
// parse multipart
// parse multipart
HashMap files = httpd . parseMultipart ( requestHeader , args , body , length ) ;
HashMap files = httpd . parseMultipart ( requestHeader , args , body , length ) ;
// integrate these files into the args
// integrate these files into the args
if ( files ! = null ) {
if ( files ! = null ) {
@ -296,245 +297,258 @@ public final class httpdFileHandler extends httpdAbstractHandler implements http
args . put ( ( ( String ) entry . getKey ( ) ) + "$file" , entry . getValue ( ) ) ;
args . put ( ( ( String ) entry . getKey ( ) ) + "$file" , entry . getValue ( ) ) ;
}
}
}
}
argc = Integer . parseInt ( ( String ) requestHeader . get ( "ARGC" ) ) ;
argc = Integer . parseInt ( ( String ) requestHeader . get ( "ARGC" ) ) ;
} else {
} else {
// parse args in body
// parse args in body
argc = httpd . parseArgs ( args , body , length ) ;
argc = httpd . parseArgs ( args , body , length ) ;
}
}
} else {
} else {
// no args
// no args
argsString = null ;
argsString = null ;
args = null ;
args = null ;
argc = 0 ;
argc = 0 ;
}
}
} else {
} else {
// simple args in URL (stuff after the "?")
// simple args in URL (stuff after the "?")
argc = httpd . parseArgs ( args , argsString ) ;
argc = httpd . parseArgs ( args , argsString ) ;
}
}
//if (args != null) System.out.println("***ARGS=" + args.toString()); // DEBUG
//if (args != null) System.out.println("***ARGS=" + args.toString()); // DEBUG
// check for cross site scripting - attacks in request arguments
// check for cross site scripting - attacks in request arguments
if ( argc > 0 ) {
if ( argc > 0 ) {
// check all values for occurrences of script values
// check all values for occurrences of script values
Enumeration e = args . elements ( ) ; // enumeration of values
Enumeration e = args . elements ( ) ; // enumeration of values
Object val ;
Object val ;
while ( e . hasMoreElements ( ) ) {
while ( e . hasMoreElements ( ) ) {
val = e . nextElement ( ) ;
val = e . nextElement ( ) ;
if ( ( val ! = null ) & & ( val instanceof String ) & & ( ( ( String ) val ) . indexOf ( "<script" ) > = 0 ) ) {
if ( ( val ! = null ) & & ( val instanceof String ) & & ( ( ( String ) val ) . indexOf ( "<script" ) > = 0 ) ) {
// deny request
// deny request
out . write ( ( "HTTP/1.0 403 bad post values\r\n" ) . getBytes ( ) ) ;
httpd . sendRespondError ( conProp , out , 4 , 403 , null , "bad post values" , null ) ;
out . write ( ( "\r\n" ) . getBytes ( ) ) ;
//httpd.sendRespondHeader(conProp,out,httpVersion,403,"bad post values",0);
out . flush ( ) ;
return ;
return ;
}
}
}
}
}
}
// we are finished with parsing
// we are finished with parsing
// the result of value hand-over is in args and argc
// the result of value hand-over is in args and argc
if ( path . length ( ) = = 0 ) {
if ( path . length ( ) = = 0 ) {
httpd . sendRespondError ( conProp , out , 4 , 400 , null , "Bad Request" , null ) ;
textMessage ( out , 400 , "Bad Request\r\n" ) ;
// textMessage(out, 400, "Bad Request\r\n");
out . flush ( ) ;
out . flush ( ) ;
return ;
return ;
}
}
Date filedate ;
Date filedate ;
long filelength ;
long filelength ;
File rc = null ;
File rc = null ;
try {
try {
// locate the file
// locate the file
if ( ! ( path . startsWith ( "/" ) ) ) {
if ( ! ( path . startsWith ( "/" ) ) ) {
// attach leading slash
// attach leading slash
path = "/" + path ;
path = "/" + path ;
}
}
// find defaults
// find defaults
String testpath = path ;
String testpath = path ;
if ( path . endsWith ( "/" ) ) {
if ( path . endsWith ( "/" ) ) {
File file ;
File file ;
// attach default file name
// attach default file name
for ( int i = 0 ; i < defaultFiles . length ; i + + ) {
for ( int i = 0 ; i < defaultFiles . length ; i + + ) {
testpath = path + defaultFiles [ i ] ;
testpath = path + defaultFiles [ i ] ;
file = new File ( htDefaultPath , testpath ) ;
file = new File ( htDefaultPath , testpath ) ;
if ( ! ( file . exists ( ) ) ) file = new File ( htDocsPath , testpath ) ;
if ( ! ( file . exists ( ) ) ) file = new File ( htDocsPath , testpath ) ;
if ( file . exists ( ) ) { path = testpath ; break ; }
if ( file . exists ( ) ) { path = testpath ; break ; }
}
}
}
}
// find locales or alternatives in htDocsPath
File defaultFile = new File ( htDefaultPath , path ) ;
File localizedFile = defaultFile ;
if ( defaultFile . exists ( ) ) {
// look if we have a localization of that file
String htLocaleSelection = switchboard . getConfig ( "htLocaleSelection" , "default" ) ;
if ( ! ( htLocaleSelection . equals ( "default" ) ) ) {
File localePath = new File ( htLocalePath , htLocaleSelection + "/" + path ) ;
if ( localePath . exists ( ) ) localizedFile = localePath ;
}
} else {
// try to find that file in the htDocsPath
defaultFile = new File ( htDocsPath , path ) ;
localizedFile = defaultFile ;
}
/ *
if ( ( iMode ) & & ( path . endsWith ( ".html" ) ) ) {
file = new File ( htRootPath , path . substring ( 0 , path . length ( ) - 4 ) + "ihtml" ) ;
if ( ! ( file . exists ( ) ) ) file = new File ( htDocsPath , path . substring ( 0 , path . length ( ) - 4 ) + "ihtml" ) ;
if ( ! ( file . exists ( ) ) ) file = new File ( htRootPath , path ) ;
if ( ! ( file . exists ( ) ) ) file = new File ( htDocsPath , path ) ;
//System.out.println("IMODE PATH = " + file.toString());
}
* /
if ( ( localizedFile . exists ( ) ) & & ( localizedFile . canRead ( ) ) ) {
// find locales or alternatives in htDocsPath
// we have found a file that can be written to the client
File defaultFile = new File ( htDefaultPath , path ) ;
// if this file uses templates, then we use the template
File localizedFile = defaultFile ;
// re-write - method to create an result
if ( defaultFile . exists ( ) ) {
serverObjects tp = new serverObjects ( ) ;
// look if we have a localization of that file
filedate = new Date ( localizedFile . lastModified ( ) ) ;
String htLocaleSelection = switchboard . getConfig ( "htLocaleSelection" , "default" ) ;
String mimeType = mimeTable . getProperty ( conProp . getProperty ( "EXT" , "" ) , "text/html" ) ;
if ( ! ( htLocaleSelection . equals ( "default" ) ) ) {
File localePath = new File ( htLocalePath , htLocaleSelection + "/" + path ) ;
if ( localePath . exists ( ) ) localizedFile = localePath ;
}
} else {
// try to find that file in the htDocsPath
defaultFile = new File ( htDocsPath , path ) ;
localizedFile = defaultFile ;
}
if ( ( localizedFile . exists ( ) ) & & ( localizedFile . canRead ( ) ) ) {
// we have found a file that can be written to the client
// if this file uses templates, then we use the template
// re-write - method to create an result
serverObjects tp = new serverObjects ( ) ;
filedate = new Date ( localizedFile . lastModified ( ) ) ;
String mimeType = this . mimeTable . getProperty ( conProp . getProperty ( "EXT" , "" ) , "text/html" ) ;
byte [ ] result ;
byte [ ] result ;
if ( path . endsWith ( "html" ) | |
boolean zipContent = requestHeader . acceptGzip ( ) & & httpd . shallTransportZipped ( "." + conProp . getProperty ( "EXT" , "" ) ) ;
path . endsWith ( "xml" ) | |
String md5String = null ;
path . endsWith ( "rss" ) | |
if ( path . endsWith ( "html" ) | |
path . endsWith ( "csv" ) | |
path . endsWith ( "xml" ) | |
path . endsWith ( "pac" ) ) {
path . endsWith ( "rss" ) | |
rc = rewriteClassFile ( defaultFile ) ;
path . endsWith ( "csv" ) | |
if ( rc ! = null ) {
path . endsWith ( "pac" ) ) {
// CGI-class: call the class to create a property for rewriting
rc = rewriteClassFile ( defaultFile ) ;
try {
if ( rc ! = null ) {
requestHeader . put ( "CLIENTIP" , conProp . getProperty ( "CLIENTIP" ) ) ;
// CGI-class: call the class to create a property for rewriting
try {
requestHeader . put ( "CLIENTIP" , conProp . getProperty ( "CLIENTIP" ) ) ;
requestHeader . put ( "PATH" , path ) ;
requestHeader . put ( "PATH" , path ) ;
// in case that there are no args given, args = null or empty hashmap
// in case that there are no args given, args = null or empty hashmap
tp = ( serverObjects ) rewriteMethod ( rc ) . invoke ( null , new Object [ ] { requestHeader , args , switchboard } ) ;
tp = ( serverObjects ) rewriteMethod ( rc ) . invoke ( null , new Object [ ] { requestHeader , args , switchboard } ) ;
// if no args given , then tp will be an empty Hashtable object (not null)
// if no args given , then tp will be an empty Hashtable object (not null)
if ( tp = = null ) tp = new serverObjects ( ) ;
if ( tp = = null ) tp = new serverObjects ( ) ;
// check if the servlets requests authentification
// check if the servlets requests authentification
if ( tp . containsKey ( "AUTHENTICATE" ) ) {
if ( tp . containsKey ( "AUTHENTICATE" ) ) {
String account = tp . get ( "AUTHENTICATE" , "" ) ;
httpHeader headers = getDefaultHeaders ( ) ;
out . write ( ( "HTTP/1.1 401 log-in required\r\n" ) . getBytes ( ) ) ;
headers . put ( httpHeader . WWW_AUTHENTICATE , "Basic realm=\"" + tp . get ( "AUTHENTICATE" , "" ) + "\"" ) ;
out . write ( ( httpHeader . WWW_AUTHENTICATE + ": Basic realm=\"" + account + "\"\r\n" ) . getBytes ( ) ) ;
httpd . sendRespondHeader ( conProp , out , httpVersion , 401 , headers ) ;
out . write ( ( "\r\n" ) . getBytes ( ) ) ;
out . flush ( ) ;
return ;
return ;
}
}
// add the application version to every rewrite table
// add the application version to every rewrite table
tp . put ( "version" , switchboard . getConfig ( "version" , "" ) ) ;
tp . put ( "version" , switchboard . getConfig ( "version" , "" ) ) ;
tp . put ( "uptime" , ( ( System . currentTimeMillis ( ) - Long . parseLong ( switchboard . getConfig ( "startupTime" , "0" ) ) ) / 1000 ) / 60 ) ; // uptime in minutes
tp . put ( "uptime" , ( ( System . currentTimeMillis ( ) - Long . parseLong ( switchboard . getConfig ( "startupTime" , "0" ) ) ) / 1000 ) / 60 ) ; // uptime in minutes
//System.out.println("respond props: " + ((tp == null) ? "null" : tp.toString())); // debug
//System.out.println("respond props: " + ((tp == null) ? "null" : tp.toString())); // debug
} catch ( InvocationTargetException e ) {
} catch ( InvocationTargetException e ) {
System . out . println ( "INTERNAL ERROR: " + e . toString ( ) + ":" +
System . out . println ( "INTERNAL ERROR: " + e . toString ( ) + ":" +
e . getMessage ( ) +
e . getMessage ( ) +
" target exception at " + rc + ": " +
" target exception at " + rc + ": " +
e . getTargetException ( ) . toString ( ) + ":" +
e . getTargetException ( ) . toString ( ) + ":" +
e . getTargetException ( ) . getMessage ( ) ) ;
e . getTargetException ( ) . getMessage ( ) ) ;
e . printStackTrace ( ) ;
e . printStackTrace ( ) ;
rc = null ;
rc = null ;
}
}
filedate = new Date ( System . currentTimeMillis ( ) ) ;
filedate = new Date ( System . currentTimeMillis ( ) ) ;
}
}
// read templates
// read templates
tp . putAll ( templates ) ;
tp . putAll ( templates ) ;
// rewrite the file
// rewrite the file
ByteArrayOutputStream o = null ;
ByteArrayOutputStream o = null ;
FileInputStream fis = null ;
FileInputStream fis = null ;
try {
GZIPOutputStream zippedOut = null ;
o = new ByteArrayOutputStream ( ) ;
try {
fis = new FileInputStream ( localizedFile ) ;
o = new ByteArrayOutputStream ( ) ;
httpTemplate . writeTemplate ( fis , o , tp , "-UNRESOLVED_PATTERN-" . getBytes ( ) ) ;
if ( zipContent ) zippedOut = new GZIPOutputStream ( o ) ;
result = o . toByteArray ( ) ;
fis = new FileInputStream ( localizedFile ) ;
} finally {
httpTemplate . writeTemplate ( fis , ( zipContent ) ? ( OutputStream ) zippedOut : ( OutputStream ) o , tp , "-UNRESOLVED_PATTERN-" . getBytes ( ) ) ;
if ( o ! = null ) try { o . close ( ) ; } catch ( Exception e ) { }
if ( zipContent ) {
if ( fis ! = null ) try { fis . close ( ) ; } catch ( Exception e ) { }
zippedOut . finish ( ) ;
}
zippedOut . flush ( ) ;
zippedOut . close ( ) ;
zippedOut = null ;
}
result = o . toByteArray ( ) ;
if ( this . md5Digest ! = null ) {
this . md5Digest . reset ( ) ;
this . md5Digest . update ( result ) ;
byte [ ] digest = this . md5Digest . digest ( ) ;
StringBuffer digestString = new StringBuffer ( ) ;
for ( int i = 0 ; i < digest . length ; i + + )
digestString . append ( Integer . toHexString ( digest [ i ] & 0xff ) ) ;
md5String = digestString . toString ( ) ;
}
} finally {
if ( zippedOut ! = null ) try { zippedOut . close ( ) ; } catch ( Exception e ) { }
if ( o ! = null ) try { o . close ( ) ; } catch ( Exception e ) { }
if ( fis ! = null ) try { fis . close ( ) ; } catch ( Exception e ) { }
}
} else { // no html
} else { // no html
// write the file to the client
// write the file to the client
result = serverFileUtils . read ( localizedFile ) ;
result = ( zipContent ) ? serverFileUtils . readAndZip ( localizedFile ) : serverFileUtils . read ( localizedFile ) ;
// check mime type again using the result array: these are 'magics'
// if (serverByteBuffer.equals(result, 1, "PNG".getBytes())) mimeType = mimeTable.getProperty("png","text/html");
// else if (serverByteBuffer.equals(result, 0, "GIF89".getBytes())) mimeType = mimeTable.getProperty("gif","text/html");
// else if (serverByteBuffer.equals(result, 6, "JFIF".getBytes())) mimeType = mimeTable.getProperty("jpg","text/html");
//System.out.print("MAGIC:"); for (int i = 0; i < 10; i++) System.out.print(Integer.toHexString((int) result[i]) + ","); System.out.println();
}
}
// check mime type again using the result array: these are 'magics'
if ( serverByteBuffer . equals ( result , 1 , "PNG" . getBytes ( ) ) ) mimeType = mimeTable . getProperty ( "png" , "text/html" ) ;
else if ( serverByteBuffer . equals ( result , 0 , "GIF89" . getBytes ( ) ) ) mimeType = mimeTable . getProperty ( "gif" , "text/html" ) ;
else if ( serverByteBuffer . equals ( result , 6 , "JFIF" . getBytes ( ) ) ) mimeType = mimeTable . getProperty ( "jpg" , "text/html" ) ;
//System.out.print("MAGIC:"); for (int i = 0; i < 10; i++) System.out.print(Integer.toHexString((int) result[i]) + ","); System.out.println();
// write the array to the client
// write the array to the client
respondHeader ( out , 200 , mimeType , result . length , filedate , null , null ) ;
httpd . sendRespondHeader ( this . connectionProperties , out , "HTTP/1.1" , 200 , null , mimeType , result . length , filedate , null , null , ( zipContent ) ? "gzip" : null , null ) ;
Thread . currentThread ( ) . sleep ( 200 ) ; // this solved the message problem (!!)
Thread . currentThread ( ) . sleep ( 200 ) ; // this solved the message problem (!!)
serverFileUtils . write ( result , out ) ;
serverFileUtils . write ( result , out ) ;
} else {
} else {
textMessage ( out , 404 , "404 File not Found\r\n" ) ; // would be a possible vuln to return original the original path
httpd . sendRespondError ( conProp , out , 3 , 404 , "File not Found" , null , null ) ;
}
//textMessage(out, 404, "404 File not Found\r\n"); // would be a possible vuln to return original the original path
} catch ( Exception e ) {
}
//textMessage(out, 503, "Exception with query: " + path + "; '" + e.toString() + ":" + e.getMessage() + "'\r\n");
} catch ( Exception e ) {
//e.printStackTrace();
//textMessage(out, 503, "Exception with query: " + path + "; '" + e.toString() + ":" + e.getMessage() + "'\r\n");
System . out . println ( "ERROR: Exception with query: " + path + "; '" + e . toString ( ) + ":" + e . getMessage ( ) + "'\r\n" ) ;
//e.printStackTrace();
}
System . out . println ( "ERROR: Exception with query: " + path + "; '" + e . toString ( ) + ":" + e . getMessage ( ) + "'\r\n" ) ;
out . flush ( ) ;
}
out . flush ( ) ;
if ( ! ( requestHeader . get ( httpHeader . CONNECTION , "close" ) . equals ( "keep-alive" ) ) ) {
if ( ! ( requestHeader . get ( httpHeader . CONNECTION , "close" ) . equals ( "keep-alive" ) ) ) {
// wait a little time until everything closes so that clients can read from the streams/sockets
// wait a little time until everything closes so that clients can read from the streams/sockets
try { Thread . currentThread ( ) . sleep ( 1000 ) ; } catch ( InterruptedException e ) { }
try { Thread . currentThread ( ) . sleep ( 1000 ) ; } catch ( InterruptedException e ) { }
}
}
}
}
private static HashMap loadTemplates ( File path ) {
private static HashMap loadTemplates ( File path ) {
// reads all templates from a path
// reads all templates from a path
// we use only the folder from the given file path
// we use only the folder from the given file path
HashMap result = new HashMap ( ) ;
HashMap result = new HashMap ( ) ;
if ( path = = null ) return result ;
if ( path = = null ) return result ;
if ( ! ( path . isDirectory ( ) ) ) path = path . getParentFile ( ) ;
if ( ! ( path . isDirectory ( ) ) ) path = path . getParentFile ( ) ;
if ( ( path = = null ) | | ( ! ( path . isDirectory ( ) ) ) ) return result ;
if ( ( path = = null ) | | ( ! ( path . isDirectory ( ) ) ) ) return result ;
String [ ] templates = path . list ( ) ;
String [ ] templates = path . list ( ) ;
int c ;
int c ;
for ( int i = 0 ; i < templates . length ; i + + ) {
for ( int i = 0 ; i < templates . length ; i + + ) {
if ( templates [ i ] . endsWith ( ".template" ) )
if ( templates [ i ] . endsWith ( ".template" ) )
try {
try {
//System.out.println("TEMPLATE " + templates[i].substring(0, templates[i].length() - 9) + ": " + new String(buf, 0, c));
//System.out.println("TEMPLATE " + templates[i].substring(0, templates[i].length() - 9) + ": " + new String(buf, 0, c));
result . put ( templates [ i ] . substring ( 0 , templates [ i ] . length ( ) - 9 ) ,
result . put ( templates [ i ] . substring ( 0 , templates [ i ] . length ( ) - 9 ) ,
new String ( serverFileUtils . read ( new File ( path , templates [ i ] ) ) ) ) ;
new String ( serverFileUtils . read ( new File ( path , templates [ i ] ) ) ) ) ;
} catch ( Exception e ) { }
} catch ( Exception e ) { }
}
}
return result ;
return result ;
}
}
private File rewriteClassFile ( File template ) {
private File rewriteClassFile ( File template ) {
try {
try {
String f = template . getCanonicalPath ( ) ;
String f = template . getCanonicalPath ( ) ;
int p = f . lastIndexOf ( "." ) ;
int p = f . lastIndexOf ( "." ) ;
if ( p < 0 ) return null ;
if ( p < 0 ) return null ;
f = f . substring ( 0 , p ) + ".class" ;
f = f . substring ( 0 , p ) + ".class" ;
//System.out.println("constructed class path " + f);
//System.out.println("constructed class path " + f);
File cf = new File ( f ) ;
File cf = new File ( f ) ;
if ( cf . exists ( ) ) return cf ;
if ( cf . exists ( ) ) return cf ;
return null ;
return null ;
} catch ( IOException e ) {
} catch ( IOException e ) {
return null ;
return null ;
}
}
}
}
private Method rewriteMethod ( File classFile ) {
private Method rewriteMethod ( File classFile ) {
Method m = null ;
Method m = null ;
// now make a class out of the stream
// now make a class out of the stream
try {
try {
//System.out.println("**DEBUG** loading class file " + classFile);
//System.out.println("**DEBUG** loading class file " + classFile);
Class c = provider . loadClass ( classFile ) ;
Class c = provider . loadClass ( classFile ) ;
Class [ ] params = new Class [ ] {
Class [ ] params = new Class [ ] {
Class . forName ( "de.anomic.http.httpHeader" ) ,
Class . forName ( "de.anomic.http.httpHeader" ) ,
Class . forName ( "de.anomic.server.serverObjects" ) ,
Class . forName ( "de.anomic.server.serverObjects" ) ,
Class . forName ( "de.anomic.server.serverSwitch" ) } ;
Class . forName ( "de.anomic.server.serverSwitch" ) } ;
m = c . getMethod ( "respond" , params ) ;
m = c . getMethod ( "respond" , params ) ;
} catch ( ClassNotFoundException e ) {
} catch ( ClassNotFoundException e ) {
System . out . println ( "INTERNAL ERROR: class " + classFile + " is missing:" + e . getMessage ( ) ) ;
System . out . println ( "INTERNAL ERROR: class " + classFile + " is missing:" + e . getMessage ( ) ) ;
} catch ( NoSuchMethodException e ) {
} catch ( NoSuchMethodException e ) {
System . out . println ( "INTERNAL ERROR: method respond not found in class " + classFile + ": " + e . getMessage ( ) ) ;
System . out . println ( "INTERNAL ERROR: method respond not found in class " + classFile + ": " + e . getMessage ( ) ) ;
}
}
//System.out.println("found method: " + m.toString());
//System.out.println("found method: " + m.toString());
return m ;
return m ;
}
}
public void doConnect ( Properties conProp , httpHeader requestHeader , InputStream clientIn , OutputStream clientOut ) {
public void doConnect ( Properties conProp , httpHeader requestHeader , InputStream clientIn , OutputStream clientOut ) {
throw new UnsupportedOperationException ( ) ;
throw new UnsupportedOperationException ( ) ;
}
}
}
}