00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 package Acme.Serve;
00033
00034 import java.io.*;
00035 import java.util.*;
00036 import java.text.*;
00037 import javax.servlet.*;
00038 import javax.servlet.http.*;
00039
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 public class FileServlet extends HttpServlet {
00057
00058
00059
00060 static Acme.WildcardDictionary throttleTab = null;
00061 static final String[] DEFAULTINDEXPAGES = {"index.html", "index.htm", "default.htm", "default.html"};
00062 static final DecimalFormat lengthftm = new DecimalFormat("#");
00063 private String basePath = null;
00064
00065 private static final boolean logenabled =
00066
00067 false;
00068
00070 public FileServlet()
00071 {
00072 }
00073
00075
00076
00077 public FileServlet( String throttles ) throws IOException
00078 {
00079 this();
00080 readThrottles( throttles );
00081 }
00082
00083 private void readThrottles( String throttles ) throws IOException
00084 {
00085 Acme.WildcardDictionary newThrottleTab =
00086 ThrottledOutputStream.parseThrottleFile( throttles );
00087 if ( throttleTab == null )
00088 throttleTab = newThrottleTab;
00089 else {
00090
00091 Enumeration keys = newThrottleTab.keys();
00092 Enumeration elements = newThrottleTab.elements();
00093 while ( keys.hasMoreElements() ) {
00094 Object key = keys.nextElement();
00095 Object element = elements.nextElement();
00096 throttleTab.put( key, element );
00097 }
00098 }
00099 }
00100
00102
00103 public String getServletInfo()
00104 {
00105 return "servlet similar to a standard httpd";
00106 }
00107
00108
00110
00111
00112
00113 public void service( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException
00114 {
00115 boolean headOnly;
00116 if ( req.getMethod().equalsIgnoreCase( "get" ) )
00117 headOnly = false;
00118 else if ( ! req.getMethod().equalsIgnoreCase( "head" ) )
00119 headOnly = true;
00120 else {
00121 res.sendError( HttpServletResponse.SC_NOT_IMPLEMENTED );
00122 return;
00123 }
00124
00125 String path = req.getPathInfo();
00126 if (path != null && path.length() > 2) {
00127 path = path.replace( '\\', '/');
00128 if ( path.indexOf( "/../" ) >0 || path.endsWith( "/.." ) ) {
00129 res.sendError( HttpServletResponse.SC_FORBIDDEN );
00130 return;
00131 }
00132 }
00133
00134 dispatchPathname( req, res, headOnly, path );
00135 }
00136
00137
00138 private void dispatchPathname( HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path ) throws IOException
00139 {
00140 String filename = req.getPathTranslated()!=null?req.getPathTranslated().replace( '/', File.separatorChar ):"";
00141 if ( filename.length() > 0 && filename.charAt( filename.length() - 1 ) == File.separatorChar )
00142 filename = filename.substring( 0, filename.length() - 1 );
00143
00144 if (this.getBasePath() != null) {
00145 filename = this.getBasePath()+filename;
00146 }
00147 File file = new File( filename );
00148 log("showing "+filename+" for path "+path);
00149 if ( file.exists() ) {
00150 if ( ! file.isDirectory() )
00151 serveFile( req, res, headOnly, path, file );
00152 else {
00153 log("showing dir "+file);
00154 if ( path.charAt( path.length() - 1 ) != '/' )
00155 redirectDirectory( req, res, path, file );
00156 else
00157 showIdexFile(req, res, headOnly, path, filename);
00158 }
00159 } else {
00160 for (int i=0; i<DEFAULTINDEXPAGES.length; i++) {
00161 if ( filename.endsWith( File.separator+DEFAULTINDEXPAGES[i] ) ) {
00162 showIdexFile(req, res, headOnly, path, file.getParent());
00163 return;
00164 }
00165 }
00166 res.sendError( HttpServletResponse.SC_NOT_FOUND );
00167 }
00168 }
00169
00170 private void showIdexFile(HttpServletRequest req, HttpServletResponse res,
00171 boolean headOnly, String path, String parent) throws IOException {
00172 log("showing index in directory "+parent);
00173 for (int i=0; i<DEFAULTINDEXPAGES.length; i++) {
00174 File indexFile = new File( parent, DEFAULTINDEXPAGES[i] );
00175 if ( indexFile.exists() ) {
00176 serveFile(req, res, headOnly, path, indexFile );
00177 return;
00178 }
00179 }
00180
00181 serveDirectory(req, res, headOnly, path, new File(parent) );
00182 }
00183
00184 private void serveFile( HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, File file ) throws IOException
00185 {
00186 log( "getting " + file );
00187 if ( ! file.canRead() ) {
00188 res.sendError( HttpServletResponse.SC_FORBIDDEN );
00189 return;
00190 }
00191
00192
00193 res.setStatus( HttpServletResponse.SC_OK );
00194 long lastMod = file.lastModified();
00195 String ifModSinceStr = req.getHeader( "If-Modified-Since" );
00196 long ifModSince = -1;
00197 if ( ifModSinceStr != null ) {
00198 int semi = ifModSinceStr.indexOf( ';' );
00199 if ( semi != -1 )
00200 ifModSinceStr = ifModSinceStr.substring( 0, semi );
00201 try {
00202 ifModSince =
00203 DateFormat.getDateInstance().parse( ifModSinceStr ).getTime();
00204 } catch ( Exception ignore ) {
00205 }
00206 }
00207 if ( ifModSince != -1 && ifModSince == lastMod ) {
00208 res.setStatus( HttpServletResponse.SC_NOT_MODIFIED );
00209 headOnly = true;
00210 }
00211
00212 res.setContentType( getServletContext().getMimeType( file.getName() ) );
00213 res.setContentLength( (int) file.length() );
00214 res.setDateHeader( "Last-modified", lastMod );
00215 OutputStream out = res.getOutputStream();
00216 if ( ! headOnly ) {
00217
00218 if ( throttleTab != null ) {
00219 ThrottleItem throttleItem =
00220 (ThrottleItem) throttleTab.get( path );
00221 if ( throttleItem != null ) {
00222
00223 out = new ThrottledOutputStream(
00224 out, throttleItem.getMaxBps() );
00225 }
00226 }
00227
00228 InputStream in = new FileInputStream( file );
00229 copyStream( in, out );
00230 in.close();
00231 }
00232 out.close();
00233 }
00234
00236
00237 public void copyStream( InputStream in, OutputStream out ) throws IOException
00238 {
00239 Acme.Utils.copyStream( in, out );
00240 }
00241
00242
00243 private void serveDirectory( HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, File file ) throws IOException
00244 {
00245 log( "indexing " + file );
00246 if ( ! file.canRead() ) {
00247 res.sendError( HttpServletResponse.SC_FORBIDDEN );
00248 return;
00249 }
00250 res.setStatus( HttpServletResponse.SC_OK );
00251 res.setContentType( "text/html" );
00252 OutputStream out = res.getOutputStream();
00253 if ( ! headOnly ) {
00254 PrintStream p = new PrintStream( new BufferedOutputStream( out ) );
00255 p.println( "<HTML><HEAD>" );
00256 p.println( "<TITLE>Index of " + path + "</TITLE>" );
00257 p.println( "</HEAD><BODY BGCOLOR=\"#F1D0F2\">" );
00258 p.println( "<H2>Index of " + path + "</H2>" );
00259 p.println( "<PRE>" );
00260 p.println( "mode bytes last-changed name" );
00261 p.println( "<HR>" );
00262 String[] names = file.list();
00263 Acme.Utils.sortStrings( names );
00264 for ( int i = 0; i < names.length; ++i ) {
00265 File aFile = new File( file, names[i] );
00266 String aFileType;
00267 if ( aFile.isDirectory() )
00268 aFileType = "d";
00269 else if ( aFile.isFile() )
00270 aFileType = "-";
00271 else
00272 aFileType = "?";
00273 String aFileRead = ( aFile.canRead() ? "r" : "-" );
00274 String aFileWrite = ( aFile.canWrite() ? "w" : "-" );
00275 String aFileExe = "-";
00276 String aFileSize = lengthftm.format( aFile.length() );
00277 while (aFileSize.length() < 12)
00278 aFileSize = " "+aFileSize;
00279 String aFileDate =
00280 Acme.Utils.lsDateStr( new Date( aFile.lastModified() ) );
00281 while (aFileDate.length() < 14)
00282 aFileDate += " ";
00283 String aFileDirsuf = ( aFile.isDirectory() ? "/" : "" );
00284 String aFileSuf = ( aFile.isDirectory() ? "/" : "" );
00285 p.println(
00286 aFileType + aFileRead + aFileWrite + aFileExe +
00287 " " + aFileSize + " " + aFileDate + " " +
00288 "<A HREF=\"" + names[i] + aFileDirsuf + "\">" +
00289 names[i] + aFileSuf + "</A>" );
00290 }
00291 p.println( "</PRE>" );
00292 p.println( "<HR>" );
00293 Serve.Identification.writeAddress( p );
00294 p.println( "</BODY></HTML>" );
00295 p.flush();
00296 }
00297 out.close();
00298 }
00299
00300
00301 private void redirectDirectory( HttpServletRequest req, HttpServletResponse res, String path, File file ) throws IOException
00302 {
00303 log( "redirecting " + path );
00304 res.sendRedirect( path + "/" );
00305 }
00306
00307 public void log(String msg)
00308 {
00309 if (logenabled)
00310 super.log(msg);
00311 }
00315 public String getBasePath() {
00316 return basePath;
00317 }
00318
00322 public void setBasePath(String string) {
00323 basePath = string;
00324 }
00325
00326 }