2005-04-07 21:19:42 +02:00
// httpdFileHandler.java
// -----------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
2005-10-05 10:40:20 +02:00
// Frankfurt, Germany, 2004, 2005
// last major change: 05.10.2005
2005-04-07 21:19:42 +02:00
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
/ *
2005-06-09 12:12:07 +02:00
Class documentation :
this class provides a file servlet and CGI interface
for the httpd server .
Whenever this server is addressed to load a local file ,
this class searches for the file in the local path as
configured in the setting property ' rootPath '
The servlet loads the file and returns it to the client .
Every file can also act as an template for the built - in
CGI interface . There is no specific path for CGI functions .
CGI functionality is triggered , if for the file to - be - served
' template . html ' also a file ' template . class ' exists . Then ,
the class file is called with the GET / POST properties that
are attached to the http call .
Possible variable hand - over are :
- form method GET
- form method POST , enctype text / plain
- form method POST , enctype multipart / form - data
The class that creates the CGI respond must have at least one
static method of the form
public static java . util . Hashtable respond ( java . util . HashMap , serverSwitch )
In the HashMap , the GET / POST variables are handed over .
The return value is a Property object that contains replacement
key / value pairs for the patterns in the template file .
The templates must have the form
either ' # [ ' < name > ' ] # ' for single attributes , or
' # { ' < enumname > ' } # ' and ' # { / ' < enumname > ' } # ' for enumerations of
values ' # [ ' < value > ' ] # ' .
A single value in repetitions / enumerations in the template has
the property key '_' < enumname > < count > '_' < value >
Please see also the example files ' test . html ' and ' test . java '
* /
2005-04-07 21:19:42 +02:00
package de.anomic.http ;
2006-04-03 00:59:53 +02:00
import java.awt.Image ;
import java.awt.image.BufferedImage ;
2005-09-12 12:47:27 +02:00
import java.io.BufferedInputStream ;
2005-09-09 13:14:22 +02:00
import java.io.ByteArrayInputStream ;
2005-05-05 07:32:19 +02:00
import java.io.File ;
import java.io.FileInputStream ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.OutputStream ;
import java.io.PushbackInputStream ;
2006-04-23 13:01:31 +02:00
import java.io.UnsupportedEncodingException ;
2005-09-09 13:14:22 +02:00
import java.lang.ref.SoftReference ;
2005-05-05 07:32:19 +02:00
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
2006-04-23 13:01:31 +02:00
import java.net.URLDecoder ;
2005-06-09 12:12:07 +02:00
import java.security.MessageDigest ;
import java.security.NoSuchAlgorithmException ;
2005-05-05 07:32:19 +02:00
import java.util.Date ;
import java.util.Enumeration ;
import java.util.HashMap ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Properties ;
2005-09-09 13:14:22 +02:00
import java.util.logging.Level ;
2005-09-22 12:30:55 +02:00
import java.util.zip.GZIPInputStream ;
2005-06-09 12:12:07 +02:00
import java.util.zip.GZIPOutputStream ;
2005-12-22 15:05:05 +01:00
2005-10-31 03:43:55 +01:00
import javax.imageio.ImageIO ;
2005-06-09 12:12:07 +02:00
2005-10-12 22:45:14 +02:00
import de.anomic.plasma.plasmaParser ;
2005-12-22 15:05:05 +01:00
import de.anomic.plasma.plasmaSwitchboard ;
2005-10-10 09:15:57 +02:00
import de.anomic.server.serverByteBuffer ;
2005-05-05 07:32:19 +02:00
import de.anomic.server.serverClassLoader ;
import de.anomic.server.serverCore ;
import de.anomic.server.serverFileUtils ;
import de.anomic.server.serverObjects ;
import de.anomic.server.serverSwitch ;
2005-06-09 12:12:07 +02:00
import de.anomic.server.logging.serverLog ;
2005-10-31 03:43:55 +01:00
import de.anomic.ymage.ymageMatrixPainter ;
import de.anomic.ymage.ymagePNGEncoderAWT ;
2005-12-22 15:05:05 +01:00
import de.anomic.ymage.ymagePainter ;
2005-04-07 21:19:42 +02:00
2005-04-15 11:06:15 +02:00
public final class httpdFileHandler extends httpdAbstractHandler implements httpdHandler {
2005-06-09 12:12:07 +02:00
2006-08-07 02:19:01 +02:00
private static final boolean safeServletsMode = false ; // if true then all servlets are called synchronized
// class variables
2005-08-31 11:22:55 +02:00
private static final Properties mimeTable = new Properties ( ) ;
2005-10-05 12:45:33 +02:00
private static final serverClassLoader provider ;
2005-09-09 13:14:22 +02:00
private static final HashMap templates = new HashMap ( ) ;
2005-10-05 12:45:33 +02:00
private static serverSwitch switchboard ;
2005-10-19 14:20:08 +02:00
private static plasmaSwitchboard sb = plasmaSwitchboard . getSwitchboard ( ) ;
2005-10-05 12:45:33 +02:00
private static File htRootPath = null ;
private static File htDocsPath = null ;
private static File htTemplatePath = null ;
private static String [ ] defaultFiles = null ;
private static File htDefaultPath = null ;
private static File htLocalePath = null ;
2005-06-09 12:12:07 +02:00
private MessageDigest md5Digest = null ;
2005-09-09 13:14:22 +02:00
/ * *
* Template Cache
* @param switchboard
* /
2005-10-10 11:13:17 +02:00
private static final HashMap templateCache ;
private static final HashMap templateMethodCache ;
2005-09-09 13:14:22 +02:00
2005-09-12 12:47:27 +02:00
public static boolean useTemplateCache = false ;
static {
useTemplateCache = plasmaSwitchboard . getSwitchboard ( ) . getConfig ( " enableTemplateCache " , " true " ) . equalsIgnoreCase ( " true " ) ;
2005-10-10 11:13:17 +02:00
templateCache = ( useTemplateCache ) ? new HashMap ( ) : new HashMap ( 0 ) ;
templateMethodCache = ( useTemplateCache ) ? new HashMap ( ) : new HashMap ( 0 ) ;
2005-10-05 12:45:33 +02:00
// create a class loader
provider = new serverClassLoader ( /*this.getClass().getClassLoader()*/ ) ;
2005-09-12 12:47:27 +02:00
}
2005-04-07 21:19:42 +02:00
public httpdFileHandler ( serverSwitch switchboard ) {
2005-07-07 15:58:54 +02:00
// creating a logger
this . theLogger = new serverLog ( " FILEHANDLER " ) ;
2005-10-05 12:45:33 +02:00
if ( httpdFileHandler . switchboard = = null ) {
httpdFileHandler . switchboard = switchboard ;
if ( mimeTable . size ( ) = = 0 ) {
// load the mime table
String mimeTablePath = switchboard . getConfig ( " mimeConfig " , " " ) ;
BufferedInputStream mimeTableInputStream = null ;
try {
serverLog . logConfig ( " HTTPDFiles " , " Loading mime mapping file " + mimeTablePath ) ;
mimeTableInputStream = new BufferedInputStream ( new FileInputStream ( new File ( switchboard . getRootPath ( ) , mimeTablePath ) ) ) ;
mimeTable . load ( mimeTableInputStream ) ;
} catch ( Exception e ) {
serverLog . logSevere ( " HTTPDFiles " , " ERROR: path to configuration file or configuration invalid \ n " + e ) ;
System . exit ( 1 ) ;
} finally {
if ( mimeTableInputStream ! = null ) try { mimeTableInputStream . close ( ) ; } catch ( Exception e1 ) { }
}
2005-06-09 12:12:07 +02:00
}
2005-10-05 12:45:33 +02:00
// create default files array
2006-08-22 15:35:51 +02:00
initDefaultPath ( ) ;
2005-10-05 12:45:33 +02:00
// create a htRootPath: system pages
if ( htRootPath = = null ) {
htRootPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( " htRootPath " , " htroot " ) ) ;
if ( ! ( htRootPath . exists ( ) ) ) htRootPath . mkdir ( ) ;
}
// create a htDocsPath: user defined pages
if ( htDocsPath = = null ) {
htDocsPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( " htDocsPath " , " htdocs " ) ) ;
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 ( ) ;
}
2005-11-21 09:33:54 +01:00
//This is now handles by #%env/templates/foo%#
//if (templates.size() == 0) templates.putAll(httpTemplate.loadTemplates(htTemplatePath));
2005-10-05 12:45:33 +02:00
// create htLocaleDefault, htLocalePath
if ( htDefaultPath = = null ) htDefaultPath = new File ( switchboard . getRootPath ( ) , switchboard . getConfig ( " htDefaultPath " , " htroot " ) ) ;
2006-02-04 11:50:22 +01:00
if ( htLocalePath = = null ) htLocalePath = new File ( switchboard . getConfig ( " htLocalePath " , " DATA/HTDOCS/locale " ) ) ;
2005-10-05 12:45:33 +02:00
//htLocaleSelection = switchboard.getConfig("htLocaleSelection","default");
2005-06-09 12:12:07 +02:00
}
2005-04-07 21:19:42 +02:00
2005-06-09 12:12:07 +02:00
// initialise an message digest for Content-MD5 support ...
try {
this . md5Digest = MessageDigest . getInstance ( " MD5 " ) ;
} catch ( NoSuchAlgorithmException e ) {
serverLog . logWarning ( " HTTPDFileHandler " , " Content-MD5 support not availabel ... " ) ;
}
2005-04-07 21:19:42 +02:00
}
2005-12-06 22:21:14 +01:00
2006-08-22 15:35:51 +02:00
public static final void initDefaultPath ( ) {
// create default files array
defaultFiles = switchboard . getConfig ( " defaultFiles " , " index.html " ) . split ( " , " ) ;
if ( defaultFiles . length = = 0 ) defaultFiles = new String [ ] { " index.html " } ;
}
2005-10-12 14:44:05 +02:00
/ *
* Returns the path of a ( existing ) localized File , or the english one , if not availible .
* @param path is relative from htroot
* @return the function returns a Filehandle to the translated file , or if not availitble to the english one .
* /
public static File getLocalizedFile ( String path ) {
plasmaSwitchboard switchboard = plasmaSwitchboard . getSwitchboard ( ) ;
// 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");
// find locales or alternatives in htDocsPath
String htLocaleSelection = switchboard . getConfig ( " htLocaleSelection " , " default " ) ;
// look if we have a localization of that file
if ( ! ( htLocaleSelection . equals ( " default " ) ) ) {
File localePath = new File ( htLocalePath , htLocaleSelection + " / " + path ) ;
if ( localePath . exists ( ) )
return localePath ;
}
return new File ( htDefaultPath , path ) ;
}
2005-04-07 21:19:42 +02:00
2005-06-09 12:12:07 +02:00
// private void textMessage(OutputStream out, int retcode, String body) throws IOException {
// httpd.sendRespondHeader(
// this.connectionProperties, // the connection properties
// 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();
// }
2005-10-12 22:45:14 +02:00
private httpHeader getDefaultHeaders ( String path ) {
2005-06-09 12:12:07 +02:00
httpHeader headers = new httpHeader ( ) ;
2005-10-12 22:45:14 +02:00
String ext ;
int pos ;
if ( ( pos = path . lastIndexOf ( '.' ) ) < 0 ) {
ext = " " ;
} else {
ext = path . substring ( pos + 1 ) . toLowerCase ( ) ;
}
2005-06-09 12:12:07 +02:00
headers . put ( httpHeader . SERVER , " AnomicHTTPD (www.anomic.de) " ) ;
headers . put ( httpHeader . DATE , httpc . dateString ( httpc . nowDate ( ) ) ) ;
2005-10-12 22:45:14 +02:00
if ( ! ( plasmaParser . mediaExtContains ( ext ) ) ) {
headers . put ( httpHeader . PRAGMA , " no-cache " ) ;
}
2005-06-09 12:12:07 +02:00
return headers ;
2005-04-07 21:19:42 +02:00
}
public void doGet ( Properties conProp , httpHeader requestHeader , OutputStream response ) throws IOException {
2005-06-09 12:12:07 +02:00
doResponse ( conProp , requestHeader , response , null ) ;
2005-04-07 21:19:42 +02:00
}
2005-06-09 12:12:07 +02:00
2005-04-07 21:19:42 +02:00
public void doHead ( Properties conProp , httpHeader requestHeader , OutputStream response ) throws IOException {
2005-06-09 12:12:07 +02:00
doResponse ( conProp , requestHeader , response , null ) ;
2005-04-07 21:19:42 +02:00
}
2005-06-09 12:12:07 +02:00
2005-04-07 21:19:42 +02:00
public void doPost ( Properties conProp , httpHeader requestHeader , OutputStream response , PushbackInputStream body ) throws IOException {
2005-06-09 12:12:07 +02:00
doResponse ( conProp , requestHeader , response , body ) ;
2005-04-07 21:19:42 +02:00
}
2005-06-09 12:12:07 +02:00
2005-09-22 12:30:55 +02:00
public void doResponse ( Properties conProp , httpHeader requestHeader , OutputStream out , InputStream body ) throws IOException {
2005-06-09 12:12:07 +02:00
this . connectionProperties = conProp ;
// getting some connection properties
2005-09-20 23:49:47 +02:00
String method = conProp . getProperty ( httpHeader . CONNECTION_PROP_METHOD ) ;
String path = conProp . getProperty ( httpHeader . CONNECTION_PROP_PATH ) ;
String argsString = conProp . getProperty ( httpHeader . CONNECTION_PROP_ARGS ) ; // is null if no args were given
String httpVersion = conProp . getProperty ( httpHeader . CONNECTION_PROP_HTTP_VER ) ;
2005-06-09 12:12:07 +02:00
// check hack attacks in path
if ( path . indexOf ( " .. " ) > = 0 ) {
2005-09-09 13:14:22 +02:00
httpd . sendRespondError ( conProp , out , 4 , 403 , null , " Access not allowed " , null ) ;
2005-06-09 12:12:07 +02:00
return ;
}
2006-04-23 13:01:31 +02:00
// url decoding of path
try {
path = URLDecoder . decode ( path , " UTF-8 " ) ;
} catch ( UnsupportedEncodingException e ) {
// This should never occur
assert ( false ) : " UnsupportedEncodingException: " + e . getMessage ( ) ;
}
2005-04-07 21:19:42 +02:00
// check permission/granted access
2005-07-30 09:15:39 +02:00
String authorization = ( String ) requestHeader . get ( httpHeader . AUTHORIZATION ) ;
String adminAccountBase64MD5 = switchboard . getConfig ( " adminAccountBase64MD5 " , " " ) ;
2006-06-12 15:47:44 +02:00
2006-02-07 07:54:23 +01:00
int pos = path . lastIndexOf ( " . " ) ;
if ( ( path . substring ( 0 , ( pos = = - 1 ) ? path . length ( ) : pos ) ) . endsWith ( " _p " ) & & ( adminAccountBase64MD5 . length ( ) ! = 0 ) ) {
2006-06-18 14:15:26 +02:00
//authentication required
//userDB
if ( sb . userDB . hasAdminRight ( authorization , conProp . getProperty ( " CLIENTIP " ) , requestHeader . getHeaderCookies ( ) ) ) {
//Authentication successful. remove brute-force flag
serverCore . bfHost . remove ( conProp . getProperty ( " CLIENTIP " ) ) ;
//static
} else if ( authorization ! = null & & sb . staticAdminAuthenticated ( authorization . trim ( ) . substring ( 6 ) ) = = 4 ) {
//Authentication successful. remove brute-force flag
serverCore . bfHost . remove ( conProp . getProperty ( " CLIENTIP " ) ) ;
//no auth
2006-06-12 15:47:44 +02:00
} else if ( authorization = = null ) {
2005-04-07 21:19:42 +02:00
// no authorization given in response. Ask for that
2005-10-12 22:45:14 +02:00
httpHeader headers = getDefaultHeaders ( path ) ;
2005-06-09 12:12:07 +02:00
headers . put ( httpHeader . WWW_AUTHENTICATE , " Basic realm= \" admin log-in \" " ) ;
2006-06-12 14:12:21 +02:00
//httpd.sendRespondHeader(conProp,out,httpVersion,401,headers);
2006-06-12 15:47:44 +02:00
serverObjects tp = new serverObjects ( ) ;
tp . put ( " returnto " , path ) ;
2006-06-18 14:15:26 +02:00
//TODO: separate errorpage Wrong Login / No Login
2006-06-12 15:47:44 +02:00
httpd . sendRespondError ( conProp , out , 5 , 401 , " Wrong Authentication " , " " , new File ( " proxymsg/authfail.inc " ) , tp , null , headers ) ;
2005-04-07 21:19:42 +02:00
return ;
2005-06-09 12:12:07 +02:00
} else {
2006-06-12 15:47:44 +02:00
// a wrong authentication was given or the userDB user does not have admin access. Ask again
2005-12-07 00:51:29 +01:00
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 + " ' " ) ;
Integer attempts = ( Integer ) serverCore . bfHost . get ( clientIP ) ;
if ( attempts = = null )
serverCore . bfHost . put ( clientIP , new Integer ( 1 ) ) ;
else
serverCore . bfHost . put ( clientIP , new Integer ( attempts . intValue ( ) + 1 ) ) ;
2005-06-09 12:12:07 +02:00
2005-12-07 00:51:29 +01:00
httpHeader headers = getDefaultHeaders ( path ) ;
headers . put ( httpHeader . WWW_AUTHENTICATE , " Basic realm= \" admin log-in \" " ) ;
httpd . sendRespondHeader ( conProp , out , httpVersion , 401 , headers ) ;
2006-06-12 15:47:44 +02:00
return ;
2005-04-07 21:19:42 +02:00
}
2005-06-09 12:12:07 +02:00
}
2005-07-30 09:15:39 +02:00
2005-06-09 12:12:07 +02:00
// parse arguments
serverObjects args = new serverObjects ( ) ;
int argc ;
if ( argsString = = null ) {
// no args here, maybe a POST with multipart extension
2005-11-29 08:27:58 +01:00
int length = 0 ;
2005-06-09 12:12:07 +02:00
//System.out.println("HEADER: " + requestHeader.toString()); // DEBUG
2005-09-22 12:30:55 +02:00
if ( method . equals ( httpHeader . METHOD_POST ) ) {
2005-10-05 12:45:33 +02:00
GZIPInputStream gzipBody = null ;
2005-09-22 12:30:55 +02:00
if ( requestHeader . containsKey ( httpHeader . CONTENT_LENGTH ) ) {
length = Integer . parseInt ( ( String ) requestHeader . get ( httpHeader . CONTENT_LENGTH ) ) ;
} else if ( requestHeader . gzip ( ) ) {
length = - 1 ;
2005-10-05 12:45:33 +02:00
gzipBody = new GZIPInputStream ( body ) ;
2005-09-22 12:30:55 +02:00
}
2005-11-29 08:27:58 +01:00
// } else {
// httpd.sendRespondError(conProp,out,4,403,null,"bad post values",null);
// return;
// }
2005-09-22 12:30:55 +02:00
2005-06-09 12:12:07 +02:00
// if its a POST, it can be either multipart or as args in the body
if ( ( requestHeader . containsKey ( httpHeader . CONTENT_TYPE ) ) & &
( ( ( String ) requestHeader . get ( httpHeader . CONTENT_TYPE ) ) . toLowerCase ( ) . startsWith ( " multipart " ) ) ) {
// parse multipart
2005-10-05 12:45:33 +02:00
HashMap files = httpd . parseMultipart ( requestHeader , args , ( gzipBody ! = null ) ? gzipBody : body , length ) ;
2005-04-07 21:19:42 +02:00
// integrate these files into the args
if ( files ! = null ) {
Iterator fit = files . entrySet ( ) . iterator ( ) ;
Map . Entry entry ;
while ( fit . hasNext ( ) ) {
entry = ( Map . Entry ) fit . next ( ) ;
args . put ( ( ( String ) entry . getKey ( ) ) + " $file " , entry . getValue ( ) ) ;
}
}
2005-06-09 12:12:07 +02:00
argc = Integer . parseInt ( ( String ) requestHeader . get ( " ARGC " ) ) ;
} else {
// parse args in body
2005-10-05 12:45:33 +02:00
argc = httpd . parseArgs ( args , ( gzipBody ! = null ) ? gzipBody : body , length ) ;
2005-06-09 12:12:07 +02:00
}
} else {
// no args
argsString = null ;
args = null ;
argc = 0 ;
}
} else {
// simple args in URL (stuff after the "?")
argc = httpd . parseArgs ( args , argsString ) ;
}
// check for cross site scripting - attacks in request arguments
if ( argc > 0 ) {
// check all values for occurrences of script values
Enumeration e = args . elements ( ) ; // enumeration of values
Object val ;
while ( e . hasMoreElements ( ) ) {
val = e . nextElement ( ) ;
if ( ( val ! = null ) & & ( val instanceof String ) & & ( ( ( String ) val ) . indexOf ( " <script " ) > = 0 ) ) {
// deny request
httpd . sendRespondError ( conProp , out , 4 , 403 , null , " bad post values " , null ) ;
return ;
}
}
}
// we are finished with parsing
// the result of value hand-over is in args and argc
if ( path . length ( ) = = 0 ) {
httpd . sendRespondError ( conProp , out , 4 , 400 , null , " Bad Request " , null ) ;
out . flush ( ) ;
return ;
}
2005-10-19 09:17:49 +02:00
File targetClass = null ;
2005-06-09 12:12:07 +02:00
try {
// locate the file
2005-10-07 00:30:13 +02:00
if ( ! ( path . startsWith ( " / " ) ) ) path = " / " + path ; // attach leading slash
2005-10-19 08:52:43 +02:00
File targetFile = getLocalizedFile ( path ) ;
2005-10-07 03:25:39 +02:00
String targetExt = conProp . getProperty ( " EXT " , " " ) ;
2005-10-20 16:58:15 +02:00
targetClass = rewriteClassFile ( new File ( htDefaultPath , path ) ) ;
2005-04-07 21:19:42 +02:00
if ( path . endsWith ( " / " ) ) {
2005-10-07 00:30:13 +02:00
String testpath ;
2005-06-09 12:12:07 +02:00
// attach default file name
2005-04-07 21:19:42 +02:00
for ( int i = 0 ; i < defaultFiles . length ; i + + ) {
testpath = path + defaultFiles [ i ] ;
2006-07-17 17:49:42 +02:00
targetFile = getOverlayedFile ( testpath ) ;
targetClass = getOverlayedClass ( testpath ) ;
2005-10-19 09:17:49 +02:00
if ( targetFile . exists ( ) ) {
path = testpath ;
break ;
}
2005-04-07 21:19:42 +02:00
}
2006-07-17 17:49:42 +02:00
//no defaultfile, send a dirlisting
if ( targetFile = = null | | ! targetFile . exists ( ) ) {
targetFile = getOverlayedFile ( " /htdocsdefault/dir.html " ) ;
targetClass = getOverlayedClass ( " /htdocsdefault/dir.html " ) ;
if ( ! ( ( targetFile ! = null & & targetFile . exists ( ) ) & & ( targetClass ! = null & & targetClass . exists ( ) ) ) ) {
httpd . sendRespondError ( this . connectionProperties , out , 3 , 500 , " dir.html or dir.class not found. " , null , null ) ;
}
}
2005-10-19 08:52:43 +02:00
} else {
2006-06-12 15:47:44 +02:00
//XXX: you cannot share a .png/.gif file with a name like a class in htroot.
2005-11-29 08:27:58 +01:00
if ( ! ( targetFile . exists ( ) ) & & ! ( ( path . endsWith ( " png " ) | | path . endsWith ( " gif " ) | | path . endsWith ( " .stream " ) ) & & targetClass ! = null ) ) {
2005-10-19 09:17:49 +02:00
targetFile = new File ( htDocsPath , path ) ;
targetClass = rewriteClassFile ( new File ( htDocsPath , path ) ) ;
}
2005-10-19 08:52:43 +02:00
2005-06-09 12:12:07 +02:00
}
2005-04-07 21:19:42 +02:00
2005-10-19 09:17:49 +02:00
//File targetClass = rewriteClassFile(targetFile);
2006-01-13 22:29:04 +01:00
//We need tp here
serverObjects tp = new serverObjects ( ) ;
2005-10-05 10:40:20 +02:00
Date targetDate ;
2005-12-07 14:26:27 +01:00
boolean nocache = false ;
2005-10-05 10:40:20 +02:00
2005-10-24 02:34:15 +02:00
if ( ( targetClass ! = null ) & & ( path . endsWith ( " png " ) ) ) {
2005-10-05 10:40:20 +02:00
// call an image-servlet to produce an on-the-fly - generated image
2006-04-03 00:59:53 +02:00
Object img = null ;
2005-10-05 10:40:20 +02:00
try {
requestHeader . put ( " CLIENTIP " , conProp . getProperty ( " CLIENTIP " ) ) ;
requestHeader . put ( " PATH " , path ) ;
// in case that there are no args given, args = null or empty hashmap
2006-08-07 02:19:01 +02:00
img = invokeServlet ( targetClass , requestHeader , args ) ;
2005-10-05 10:40:20 +02:00
} catch ( InvocationTargetException e ) {
this . theLogger . logSevere ( " INTERNAL ERROR: " + e . toString ( ) + " : " +
e . getMessage ( ) +
" target exception at " + targetClass + " : " +
e . getTargetException ( ) . toString ( ) + " : " +
2005-10-11 09:46:14 +02:00
e . getTargetException ( ) . getMessage ( ) +
" ; java.awt.graphicsenv=' " + System . getProperty ( " java.awt.graphicsenv " , " " ) + " ' " , e ) ;
2005-10-05 10:40:20 +02:00
targetClass = null ;
2005-06-09 12:12:07 +02:00
}
2006-04-03 00:59:53 +02:00
if ( img = = null ) {
2005-10-09 16:46:33 +02:00
// error with image generation; send file-not-found
httpd . sendRespondError ( this . connectionProperties , out , 3 , 404 , " File not Found " , null , null ) ;
} else {
2006-04-03 00:59:53 +02:00
if ( img instanceof ymagePainter ) {
ymagePainter yp = ( ymagePainter ) img ;
// send an image to client
targetDate = new Date ( System . currentTimeMillis ( ) ) ;
nocache = true ;
String mimeType = mimeTable . getProperty ( targetExt , " text/html " ) ;
// generate an byte array from the generated image
serverByteBuffer baos = new serverByteBuffer ( ) ;
// ymagePNGEncoderJDE jde = new
// ymagePNGEncoderJDE((ymageMatrixPainter) yp,
// ymagePNGEncoderJDE.FILTER_NONE, 0);
// byte[] result = jde.pngEncode();
ImageIO . write ( ymagePNGEncoderAWT . toImage (
( ymageMatrixPainter ) yp , true ) ,
targetExt , baos ) ;
byte [ ] result = baos . toByteArray ( ) ;
baos . close ( ) ;
baos = null ;
// write the array to the client
httpd . sendRespondHeader ( this . connectionProperties , out ,
httpVersion , 200 , null , mimeType ,
result . length , targetDate , null , null , null ,
null , nocache ) ;
if ( ! method . equals ( httpHeader . METHOD_HEAD ) ) {
Thread . sleep ( 200 ) ; // see below
serverFileUtils . write ( result , out ) ;
}
}
if ( img instanceof Image ) {
Image i = ( Image ) img ;
// send an image to client
targetDate = new Date ( System . currentTimeMillis ( ) ) ;
nocache = true ;
String mimeType = mimeTable . getProperty ( targetExt , " text/html " ) ;
// generate an byte array from the generated image
2006-04-11 00:34:47 +02:00
int width = i . getWidth ( null ) ;
int height = i . getHeight ( null ) ;
BufferedImage bi = new BufferedImage ( width , height , BufferedImage . TYPE_INT_RGB ) ;
bi . createGraphics ( ) . drawImage ( i , 0 , 0 , width , height , null ) ;
2006-04-03 00:59:53 +02:00
serverByteBuffer baos = new serverByteBuffer ( ) ;
ImageIO . write ( bi , targetExt , baos ) ;
byte [ ] result = baos . toByteArray ( ) ;
baos . close ( ) ;
baos = null ;
// write the array to the client
httpd . sendRespondHeader ( this . connectionProperties , out ,
httpVersion , 200 , null , mimeType ,
result . length , targetDate , null , null , null ,
null , nocache ) ;
if ( ! method . equals ( httpHeader . METHOD_HEAD ) ) {
Thread . sleep ( 200 ) ; // see below
serverFileUtils . write ( result , out ) ;
}
2005-12-09 18:35:45 +01:00
}
2005-10-09 16:46:33 +02:00
}
2005-11-29 08:27:58 +01:00
} else if ( ( targetClass ! = null ) & & ( path . endsWith ( " .stream " ) ) ) {
// call rewrite-class
requestHeader . put ( " CLIENTIP " , conProp . getProperty ( " CLIENTIP " ) ) ;
requestHeader . put ( " PATH " , path ) ;
requestHeader . put ( " INPUTSTREAM " , body ) ;
requestHeader . put ( " OUTPUTSTREAM " , out ) ;
httpd . sendRespondHeader ( this . connectionProperties , out , httpVersion , 200 , null ) ;
// in case that there are no args given, args = null or empty hashmap
2006-08-07 02:19:01 +02:00
/* serverObjects tp = (serverObjects) */ invokeServlet ( targetClass , requestHeader , args ) ;
2005-11-29 08:27:58 +01:00
this . forceConnectionClose ( ) ;
return ;
2005-10-05 10:40:20 +02:00
} else if ( ( targetFile . exists ( ) ) & & ( targetFile . canRead ( ) ) ) {
2005-06-09 12:12:07 +02:00
// 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
2005-10-05 10:40:20 +02:00
String mimeType = mimeTable . getProperty ( targetExt , " text/html " ) ;
2005-04-07 21:19:42 +02:00
byte [ ] result ;
2005-06-09 12:12:07 +02:00
boolean zipContent = requestHeader . acceptGzip ( ) & & httpd . shallTransportZipped ( " . " + conProp . getProperty ( " EXT " , " " ) ) ;
if ( path . endsWith ( " html " ) | |
path . endsWith ( " xml " ) | |
path . endsWith ( " rss " ) | |
path . endsWith ( " csv " ) | |
2006-02-06 15:41:59 +01:00
path . endsWith ( " pac " ) | |
2006-07-17 17:49:42 +02:00
path . endsWith ( " src " ) | |
path . endsWith ( " / " ) ) {
2005-10-05 10:40:20 +02:00
2006-07-17 17:49:42 +02:00
/ * targetFile = getLocalizedFile ( path ) ;
2005-10-14 13:50:11 +02:00
if ( ! ( targetFile . exists ( ) ) ) {
// try to find that file in the htDocsPath
File trialFile = new File ( htDocsPath , path ) ;
if ( trialFile . exists ( ) ) targetFile = trialFile ;
2006-07-17 17:49:42 +02:00
} * /
2005-10-14 13:50:11 +02:00
2005-10-05 10:40:20 +02:00
// call rewrite-class
2006-01-13 22:29:04 +01:00
2005-10-05 10:40:20 +02:00
if ( targetClass = = null ) {
targetDate = new Date ( targetFile . lastModified ( ) ) ;
} else {
2005-06-09 12:12:07 +02:00
// CGI-class: call the class to create a property for rewriting
try {
requestHeader . put ( " CLIENTIP " , conProp . getProperty ( " CLIENTIP " ) ) ;
2005-04-07 21:19:42 +02:00
requestHeader . put ( " PATH " , path ) ;
2005-06-09 12:12:07 +02:00
// in case that there are no args given, args = null or empty hashmap
2006-08-07 02:19:01 +02:00
tp = ( serverObjects ) invokeServlet ( targetClass , requestHeader , args ) ;
2005-06-09 12:12:07 +02:00
// if no args given , then tp will be an empty Hashtable object (not null)
if ( tp = = null ) tp = new serverObjects ( ) ;
2005-04-07 21:19:42 +02:00
// check if the servlets requests authentification
if ( tp . containsKey ( " AUTHENTICATE " ) ) {
2005-07-30 09:15:39 +02:00
// handle brute-force protection
if ( authorization ! = null ) {
String clientIP = conProp . getProperty ( " CLIENTIP " , " unknown-host " ) ;
serverLog . logInfo ( " HTTPD " , " dynamic log-in for account 'admin' in http file handler for path ' " + path + " ' from host ' " + clientIP + " ' " ) ;
Integer attempts = ( Integer ) serverCore . bfHost . get ( clientIP ) ;
if ( attempts = = null )
serverCore . bfHost . put ( clientIP , new Integer ( 1 ) ) ;
else
serverCore . bfHost . put ( clientIP , new Integer ( attempts . intValue ( ) + 1 ) ) ;
}
// send authentication request to browser
2005-10-12 22:45:14 +02:00
httpHeader headers = getDefaultHeaders ( path ) ;
2005-06-09 12:12:07 +02:00
headers . put ( httpHeader . WWW_AUTHENTICATE , " Basic realm= \" " + tp . get ( " AUTHENTICATE " , " " ) + " \" " ) ;
httpd . sendRespondHeader ( conProp , out , httpVersion , 401 , headers ) ;
2005-04-07 21:19:42 +02:00
return ;
2005-09-01 09:52:46 +02:00
} else if ( tp . containsKey ( " LOCATION " ) ) {
String location = tp . get ( " LOCATION " , " " ) ;
if ( location . length ( ) = = 0 ) location = path ;
2005-10-12 22:45:14 +02:00
httpHeader headers = getDefaultHeaders ( path ) ;
2006-06-18 14:15:26 +02:00
headers . setCookieVector ( tp . getOutgoingHeader ( ) . getCookieVector ( ) ) ; //put the cookies into the new header TODO: can we put all headerlines, without trouble?
2005-09-01 09:52:46 +02:00
headers . put ( httpHeader . LOCATION , location ) ;
2005-09-12 13:38:46 +02:00
httpd . sendRespondHeader ( conProp , out , httpVersion , 302 , headers ) ;
2005-09-01 09:52:46 +02:00
return ;
2005-04-07 21:19:42 +02:00
}
2005-08-14 17:45:48 +02:00
// add the application version, the uptime and the client name to every rewrite table
2005-06-09 12:12:07 +02:00
tp . put ( " version " , switchboard . getConfig ( " version " , " " ) ) ;
tp . put ( " uptime " , ( ( System . currentTimeMillis ( ) - Long . parseLong ( switchboard . getConfig ( " startupTime " , " 0 " ) ) ) / 1000 ) / 60 ) ; // uptime in minutes
2005-08-14 17:45:48 +02:00
tp . put ( " clientname " , switchboard . getConfig ( " peerName " , " anomic " ) ) ;
2005-06-09 12:12:07 +02:00
//System.out.println("respond props: " + ((tp == null) ? "null" : tp.toString())); // debug
} catch ( InvocationTargetException e ) {
2005-10-18 09:45:27 +02:00
if ( e . getCause ( ) instanceof InterruptedException ) {
throw new InterruptedException ( e . getCause ( ) . getMessage ( ) ) ;
}
2005-08-30 23:32:59 +02:00
this . theLogger . logSevere ( " INTERNAL ERROR: " + e . toString ( ) + " : " +
2005-06-09 12:12:07 +02:00
e . getMessage ( ) +
2005-10-05 10:40:20 +02:00
" target exception at " + targetClass + " : " +
2005-06-09 12:12:07 +02:00
e . getTargetException ( ) . toString ( ) + " : " +
2005-06-10 11:19:24 +02:00
e . getTargetException ( ) . getMessage ( ) , e ) ;
2005-10-05 10:40:20 +02:00
targetClass = null ;
2005-10-20 11:55:12 +02:00
throw e ;
2005-06-09 12:12:07 +02:00
}
2005-10-05 10:40:20 +02:00
targetDate = new Date ( System . currentTimeMillis ( ) ) ;
2005-12-07 14:26:27 +01:00
nocache = true ;
2005-06-09 12:12:07 +02:00
}
// read templates
tp . putAll ( templates ) ;
2005-09-09 13:14:22 +02:00
2005-06-09 12:12:07 +02:00
// rewrite the file
2005-10-10 09:15:57 +02:00
serverByteBuffer o = null ;
2005-09-09 13:14:22 +02:00
InputStream fis = null ;
2005-06-09 12:12:07 +02:00
GZIPOutputStream zippedOut = null ;
try {
2005-09-09 13:14:22 +02:00
// do fileCaching here
byte [ ] templateContent = null ;
2005-09-12 12:47:27 +02:00
if ( useTemplateCache ) {
2005-10-05 10:40:20 +02:00
long fileSize = targetFile . length ( ) ;
2005-09-12 12:47:27 +02:00
if ( fileSize < = 512 * 1024 ) {
2005-10-05 10:40:20 +02:00
SoftReference ref = ( SoftReference ) templateCache . get ( targetFile ) ;
2005-09-12 12:47:27 +02:00
if ( ref ! = null ) {
templateContent = ( byte [ ] ) ref . get ( ) ;
if ( templateContent = = null )
2005-10-05 10:40:20 +02:00
templateCache . remove ( targetFile ) ;
2005-09-12 12:47:27 +02:00
}
if ( templateContent = = null ) {
// loading the content of the template file into a byte array
2005-10-05 10:40:20 +02:00
templateContent = serverFileUtils . read ( targetFile ) ;
2005-09-12 12:47:27 +02:00
// storing the content into the cache
ref = new SoftReference ( templateContent ) ;
2005-10-05 10:40:20 +02:00
templateCache . put ( targetFile , ref ) ;
2005-09-12 12:47:27 +02:00
if ( this . theLogger . isLoggable ( Level . FINEST ) )
2005-10-05 10:40:20 +02:00
this . theLogger . logFinest ( " Cache MISS for file " + targetFile ) ;
2005-09-12 12:47:27 +02:00
} else {
if ( this . theLogger . isLoggable ( Level . FINEST ) )
2005-10-05 10:40:20 +02:00
this . theLogger . logFinest ( " Cache HIT for file " + targetFile ) ;
2005-09-12 12:47:27 +02:00
}
2005-09-09 13:14:22 +02:00
2005-09-12 12:47:27 +02:00
// creating an inputstream needed by the template rewrite function
fis = new ByteArrayInputStream ( templateContent ) ;
templateContent = null ;
2005-09-09 13:14:22 +02:00
} else {
2005-10-05 10:40:20 +02:00
fis = new BufferedInputStream ( new FileInputStream ( targetFile ) ) ;
2005-09-09 13:14:22 +02:00
}
} else {
2005-10-05 10:40:20 +02:00
fis = new BufferedInputStream ( new FileInputStream ( targetFile ) ) ;
2005-09-09 13:14:22 +02:00
}
2006-07-18 17:51:19 +02:00
//use the page template
2006-07-19 09:08:15 +02:00
String supertemplate = " " ;
if ( tp . containsKey ( " SUPERTEMPLATE " ) ) {
supertemplate = ( String ) tp . get ( " SUPERTEMPLATE " ) ;
}
//if(sb.getConfig("usePageTemplate", "false").equals("true")){
if ( ! supertemplate . equals ( " " ) ) {
2006-07-18 17:51:19 +02:00
o = new serverByteBuffer ( ) ;
2006-07-19 09:08:15 +02:00
/ * File pageFile = getOverlayedFile ( " /env/page.html " ) ;
File pageClass = getOverlayedClass ( " /env/page.html " ) ; * /
File pageFile = getOverlayedFile ( supertemplate ) ;
File pageClass = getOverlayedClass ( supertemplate ) ;
2006-07-18 17:51:19 +02:00
if ( pageFile ! = null & & pageFile . exists ( ) ) {
//warning: o,tp and fis are reused
httpTemplate . writeTemplate ( fis , o , tp , " -UNRESOLVED_PATTERN- " . getBytes ( ) ) ;
2006-08-07 02:19:01 +02:00
if ( pageClass ! = null & & pageClass . exists ( ) )
tp = ( serverObjects ) invokeServlet ( pageClass , requestHeader , args ) ;
2006-07-18 17:51:19 +02:00
else
tp = new serverObjects ( ) ;
tp . put ( " page " , o . toString ( ) ) ;
fis = new BufferedInputStream ( new FileInputStream ( pageFile ) ) ;
}
}
2005-10-10 09:15:57 +02:00
o = new serverByteBuffer ( ) ;
2005-06-09 12:12:07 +02:00
if ( zipContent ) zippedOut = new GZIPOutputStream ( o ) ;
httpTemplate . writeTemplate ( fis , ( zipContent ) ? ( OutputStream ) zippedOut : ( OutputStream ) o , tp , " -UNRESOLVED_PATTERN- " . getBytes ( ) ) ;
if ( zipContent ) {
zippedOut . finish ( ) ;
zippedOut . flush ( ) ;
zippedOut . close ( ) ;
zippedOut = null ;
}
2006-07-18 17:51:19 +02:00
2005-06-09 12:12:07 +02:00
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 ) ) ;
}
} finally {
if ( zippedOut ! = null ) try { zippedOut . close ( ) ; } catch ( Exception e ) { }
2005-06-16 10:34:52 +02:00
if ( o ! = null ) try { o . close ( ) ; o = null ; } catch ( Exception e ) { }
2005-09-09 13:14:22 +02:00
if ( fis ! = null ) try { fis . close ( ) ; fis = null ; } catch ( Exception e ) { }
2005-06-09 12:12:07 +02:00
}
2005-05-08 09:24:33 +02:00
2006-02-15 13:31:52 +01:00
// write the array to the client
2006-02-16 11:27:21 +01:00
long contentLength = result . length ;
String contentEncoding = ( zipContent ) ? " gzip " : null ;
2006-02-15 13:51:24 +01:00
httpd . sendRespondHeader ( this . connectionProperties , out , httpVersion , 200 , null , mimeType , contentLength , targetDate , null , tp . getOutgoingHeader ( ) , contentEncoding , null , nocache ) ;
2006-02-15 13:31:52 +01:00
if ( ! method . equals ( httpHeader . METHOD_HEAD ) ) {
Thread . sleep ( 200 ) ; // this solved the message problem (!!)
serverFileUtils . write ( result , out ) ;
}
2006-02-16 10:23:27 +01:00
} else { // no html
int statusCode = 200 ;
int rangeStartOffset = 0 ;
httpHeader header = new httpHeader ( ) ;
// adding the accept ranges header
header . put ( httpHeader . ACCEPT_RANGES , " bytes " ) ;
// reading the files md5 hash if availabe and use it as ETAG of the resource
String targetMD5 = null ;
File targetMd5File = new File ( targetFile + " .md5 " ) ;
try {
if ( targetMd5File . exists ( ) ) {
2006-02-19 01:39:16 +01:00
//String description = null;
2006-02-16 10:23:27 +01:00
targetMD5 = new String ( serverFileUtils . read ( targetMd5File ) ) ;
pos = targetMD5 . indexOf ( '\n' ) ;
if ( pos > = 0 ) {
2006-02-19 01:39:16 +01:00
//description = targetMD5.substring(pos + 1);
2006-02-16 10:23:27 +01:00
targetMD5 = targetMD5 . substring ( 0 , pos ) ;
}
// using the checksum as ETAG header
header . put ( httpHeader . ETAG , targetMD5 ) ;
}
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
if ( requestHeader . containsKey ( httpHeader . RANGE ) ) {
Object ifRange = requestHeader . ifRange ( ) ;
if ( ( ifRange = = null ) | |
( ifRange instanceof Date & & targetFile . lastModified ( ) = = ( ( Date ) ifRange ) . getTime ( ) ) | |
( ifRange instanceof String & & ifRange . equals ( targetMD5 ) ) ) {
String rangeHeaderVal = ( ( String ) requestHeader . get ( httpHeader . RANGE ) ) . trim ( ) ;
if ( rangeHeaderVal . startsWith ( " bytes= " ) ) {
String rangesVal = rangeHeaderVal . substring ( " bytes= " . length ( ) ) ;
String [ ] ranges = rangesVal . split ( " , " ) ;
if ( ( ranges . length = = 1 ) & & ( ranges [ 0 ] . endsWith ( " - " ) ) ) {
rangeStartOffset = Integer . valueOf ( ranges [ 0 ] . substring ( 0 , ranges [ 0 ] . length ( ) - 1 ) ) . intValue ( ) ;
statusCode = 206 ;
if ( header = = null ) header = new httpHeader ( ) ;
header . put ( httpHeader . CONTENT_RANGE , " bytes " + rangeStartOffset + " - " + ( targetFile . length ( ) - 1 ) + " / " + targetFile . length ( ) ) ;
}
}
}
}
2005-04-07 21:19:42 +02:00
// write the file to the client
2005-10-05 10:40:20 +02:00
targetDate = new Date ( targetFile . lastModified ( ) ) ;
2006-02-16 11:27:21 +01:00
long contentLength = ( zipContent ) ? - 1 : targetFile . length ( ) - rangeStartOffset ;
String contentEncoding = ( zipContent ) ? " gzip " : null ;
2006-02-15 13:31:52 +01:00
String transferEncoding = ( ! httpVersion . equals ( httpHeader . HTTP_VERSION_1_1 ) ) ? null : ( zipContent ) ? " chunked " : null ;
if ( ! httpVersion . equals ( httpHeader . HTTP_VERSION_1_1 ) & & zipContent ) forceConnectionClose ( ) ;
2006-02-16 10:23:27 +01:00
httpd . sendRespondHeader ( this . connectionProperties , out , httpVersion , statusCode , null , mimeType , contentLength , targetDate , null , header , contentEncoding , transferEncoding , nocache ) ;
2006-02-15 13:31:52 +01:00
if ( ! method . equals ( httpHeader . METHOD_HEAD ) ) {
httpChunkedOutputStream chunkedOut = null ;
GZIPOutputStream zipped = null ;
OutputStream newOut = out ;
if ( transferEncoding ! = null ) {
chunkedOut = new httpChunkedOutputStream ( newOut ) ;
newOut = chunkedOut ;
}
if ( contentEncoding ! = null ) {
zipped = new GZIPOutputStream ( newOut ) ;
newOut = zipped ;
}
2006-02-16 10:23:27 +01:00
serverFileUtils . copyRange ( targetFile , newOut , rangeStartOffset ) ;
2006-02-15 13:31:52 +01:00
if ( zipped ! = null ) {
zipped . flush ( ) ;
zipped . finish ( ) ;
}
if ( chunkedOut ! = null ) {
chunkedOut . finish ( ) ;
}
}
2005-06-09 12:12:07 +02:00
// 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");
2006-02-15 13:31:52 +01:00
//System.out.print("MAGIC:"); for (int i = 0; i < 10; i++) System.out.print(Integer.toHexString((int) result[i]) + ","); System.out.println();
2005-12-09 18:35:45 +01:00
}
2005-06-09 12:12:07 +02:00
} else {
httpd . sendRespondError ( conProp , out , 3 , 404 , " File not Found " , null , null ) ;
2005-07-07 15:58:54 +02:00
return ;
2005-06-09 12:12:07 +02:00
}
2005-07-04 13:09:48 +02:00
} catch ( Exception e ) {
2005-07-07 15:58:54 +02:00
try {
// doing some errorhandling ...
int httpStatusCode = 400 ;
String httpStatusText = null ;
StringBuffer errorMessage = new StringBuffer ( ) ;
Exception errorExc = null ;
2005-08-04 13:05:04 +02:00
String errorMsg = e . getMessage ( ) ;
if (
( e instanceof InterruptedException ) | |
( ( errorMsg ! = null ) & & ( errorMsg . startsWith ( " Socket closed " ) ) & & ( Thread . currentThread ( ) . isInterrupted ( ) ) )
) {
2005-07-07 15:58:54 +02:00
errorMessage . append ( " Interruption detected while processing query. " ) ;
httpStatusCode = 503 ;
2005-06-13 09:50:35 +02:00
} else {
2005-07-07 15:58:54 +02:00
if ( ( errorMsg ! = null ) & &
(
errorMsg . startsWith ( " Broken pipe " ) | |
errorMsg . startsWith ( " Connection reset " ) | |
2005-08-04 13:05:04 +02:00
errorMsg . startsWith ( " Software caused connection abort " )
2005-07-07 15:58:54 +02:00
) ) {
// client closed the connection, so we just end silently
errorMessage . append ( " Client unexpectedly closed connection while processing query. " ) ;
2005-08-04 13:05:04 +02:00
} else if ( ( errorMsg ! = null ) & & ( errorMsg . startsWith ( " Connection timed out " ) ) ) {
errorMessage . append ( " Connection timed out. " ) ;
2005-06-13 09:50:35 +02:00
} else {
2005-07-07 15:58:54 +02:00
errorMessage . append ( " Unexpected error while processing query. " ) ;
httpStatusCode = 500 ;
errorExc = e ;
2005-06-13 09:50:35 +02:00
}
}
2005-07-07 15:58:54 +02:00
2005-08-04 13:05:04 +02:00
errorMessage . append ( " \ nSession: " ) . append ( Thread . currentThread ( ) . getName ( ) )
. append ( " \ nQuery: " ) . append ( path )
2005-09-20 23:49:47 +02:00
. append ( " \ nClient: " ) . append ( conProp . getProperty ( httpHeader . CONNECTION_PROP_CLIENTIP , " unknown " ) )
2005-08-04 13:05:04 +02:00
. append ( " \ nReason: " ) . append ( e . toString ( ) ) ;
2005-07-07 15:58:54 +02:00
2005-09-20 23:49:47 +02:00
if ( ! conProp . containsKey ( httpHeader . CONNECTION_PROP_PROXY_RESPOND_HEADER ) ) {
2005-07-07 15:58:54 +02:00
// sending back an error message to the client
// if we have not already send an http header
httpd . sendRespondError ( conProp , out , 4 , httpStatusCode , httpStatusText , errorMessage . toString ( ) , errorExc ) ;
} else {
// otherwise we close the connection
this . forceConnectionClose ( ) ;
}
// if it is an unexpected error we log it
if ( httpStatusCode = = 500 ) {
this . theLogger . logWarning ( errorMessage . toString ( ) , e ) ;
}
} catch ( Exception ee ) {
this . forceConnectionClose ( ) ;
}
2005-06-13 09:50:35 +02:00
} finally {
try { out . flush ( ) ; } catch ( Exception e ) { }
2006-06-20 07:22:55 +02:00
if ( ( ( String ) requestHeader . get ( httpHeader . CONNECTION , " close " ) ) . indexOf ( " keep-alive " ) = = - 1 ) {
2005-06-13 09:50:35 +02:00
// wait a little time until everything closes so that clients can read from the streams/sockets
2005-07-04 13:09:48 +02:00
try { Thread . sleep ( 1000 ) ; } catch ( InterruptedException e ) { }
2005-06-13 09:50:35 +02:00
}
2005-04-07 21:19:42 +02:00
}
}
2006-08-07 02:19:01 +02:00
2006-07-17 17:49:42 +02:00
private File getOverlayedClass ( String path ) {
File targetClass ;
targetClass = rewriteClassFile ( new File ( htDefaultPath , path ) ) ; //works for default and localized files
if ( targetClass = = null | | ! targetClass . exists ( ) ) {
//works for htdocs
targetClass = rewriteClassFile ( new File ( htDocsPath , path ) ) ;
}
return targetClass ;
}
private File getOverlayedFile ( String path ) {
File targetFile ;
targetFile = getLocalizedFile ( path ) ;
if ( ! ( targetFile . exists ( ) ) ) {
targetFile = new File ( htDocsPath , path ) ;
}
return targetFile ;
}
2005-06-09 12:12:07 +02:00
2005-07-07 15:58:54 +02:00
private void forceConnectionClose ( ) {
if ( this . connectionProperties ! = null ) {
2005-09-20 23:49:47 +02:00
this . connectionProperties . setProperty ( httpHeader . CONNECTION_PROP_PERSISTENT , " close " ) ;
2005-07-07 15:58:54 +02:00
}
}
2005-04-07 21:19:42 +02:00
private File rewriteClassFile ( File template ) {
2005-06-09 12:12:07 +02:00
try {
String f = template . getCanonicalPath ( ) ;
int p = f . lastIndexOf ( " . " ) ;
if ( p < 0 ) return null ;
f = f . substring ( 0 , p ) + " .class " ;
//System.out.println("constructed class path " + f);
File cf = new File ( f ) ;
if ( cf . exists ( ) ) return cf ;
return null ;
} catch ( IOException e ) {
return null ;
}
2005-04-07 21:19:42 +02:00
}
2005-06-09 12:12:07 +02:00
2005-10-10 11:13:17 +02:00
private final Method rewriteMethod ( File classFile ) {
2005-06-09 12:12:07 +02:00
Method m = null ;
// now make a class out of the stream
try {
2005-10-10 11:13:17 +02:00
if ( useTemplateCache ) {
SoftReference ref = ( SoftReference ) templateMethodCache . get ( classFile ) ;
if ( ref ! = null ) {
m = ( Method ) ref . get ( ) ;
if ( m = = null ) {
templateMethodCache . remove ( classFile ) ;
} else {
this . theLogger . logFine ( " Cache HIT for file " + classFile ) ;
return m ;
}
}
}
2005-06-09 12:12:07 +02:00
//System.out.println("**DEBUG** loading class file " + classFile);
Class c = provider . loadClass ( classFile ) ;
Class [ ] params = new Class [ ] {
Class . forName ( " de.anomic.http.httpHeader " ) ,
Class . forName ( " de.anomic.server.serverObjects " ) ,
Class . forName ( " de.anomic.server.serverSwitch " ) } ;
m = c . getMethod ( " respond " , params ) ;
2005-10-10 11:13:17 +02:00
if ( useTemplateCache ) {
// storing the method into the cache
SoftReference ref = new SoftReference ( m ) ;
templateMethodCache . put ( classFile , ref ) ;
this . theLogger . logFine ( " Cache MISS for file " + classFile ) ;
}
2005-06-09 12:12:07 +02:00
} catch ( ClassNotFoundException e ) {
System . out . println ( " INTERNAL ERROR: class " + classFile + " is missing: " + e . getMessage ( ) ) ;
} catch ( NoSuchMethodException e ) {
System . out . println ( " INTERNAL ERROR: method respond not found in class " + classFile + " : " + e . getMessage ( ) ) ;
}
//System.out.println("found method: " + m.toString());
return m ;
2005-04-07 21:19:42 +02:00
}
2005-06-09 12:12:07 +02:00
2006-08-07 02:19:01 +02:00
private Object invokeServlet ( File targetClass , httpHeader request , serverObjects args ) throws IllegalArgumentException , IllegalAccessException , InvocationTargetException {
Object result ;
if ( safeServletsMode ) synchronized ( switchboard ) {
result = rewriteMethod ( targetClass ) . invoke ( null , new Object [ ] { request , args , switchboard } ) ;
} else {
result = rewriteMethod ( targetClass ) . invoke ( null , new Object [ ] { request , args , switchboard } ) ;
}
return result ;
}
2005-04-07 21:19:42 +02:00
public void doConnect ( Properties conProp , httpHeader requestHeader , InputStream clientIn , OutputStream clientOut ) {
throw new UnsupportedOperationException ( ) ;
}
2005-06-09 12:12:07 +02:00
2005-04-07 21:19:42 +02:00
}