Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

external/Acme/Serve/FileServlet.java

00001 // FileServlet - servlet similar to a standard httpd
00002 //
00003 // Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.
00004 //
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions
00007 // are met:
00008 // 1. Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 // 2. Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //
00014 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00015 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00016 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00017 // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00018 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00019 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00020 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00021 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00022 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00023 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00024 // SUCH DAMAGE.
00025 //
00026 // Visit the ACME Labs Java page for up-to-date versions of this and other
00027 // fine Java utilities: http://www.acme.com/java/
00028 // 
00029 // All enhancments Copyright (C)1998,2000 by Dmitriy Rogatkin
00030 // http://tjws.sourceforge.net
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 // <P>
00042 // Implements the "GET" and "HEAD" methods for files and directories.
00043 // Handles index.html, index.htm, default.htm, default.html.
00044 // Redirects directory URLs that lack a trailing /.
00045 // Handles If-Modified-Since.
00046 // <P>
00047 // <A HREF="/resources/classes/Acme/Serve/FileServlet.java">Fetch the software.</A><BR>
00048 // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
00049 // <P>
00050 // @see Acme.Serve.Serve
00051 
00052 // All enhancments Copyright (C)1998-2000 by Dmitriy Rogatkin
00053 // this version is compatible with the latest JSDK 2.2
00054 // http://tjws.sourceforge.net
00055 
00056 public class FileServlet extends HttpServlet {
00057 
00058     // We keep a single throttle table for all instances of the servlet.
00059     // Normally there is only one instance; the exception is subclasses.
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 //              true;
00067                 false;
00068 
00070     public FileServlet()
00071     {
00072     }
00073 
00075     // @param throttles filename containing throttle settings
00076     // @see ThrottledOutputStream
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             // Merge the new one into the old one.
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     // copyright of the servlet.
00103     public String getServletInfo()
00104     {
00105         return "servlet similar to a standard httpd";
00106     }
00107 
00108 
00110     // @param req the servlet request
00111     // @param req the servlet response
00112     // @exception ServletException when an exception has occurred
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        //modif tochange path with user.dir
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                 // index not found
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         // Handle If-Modified-Since.
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             // Check throttle.
00218             if ( throttleTab != null ) {
00219                 ThrottleItem throttleItem =
00220                 (ThrottleItem) throttleTab.get( path );
00221                 if ( throttleItem != null ) {
00222                     // !!! Need to account for multiple simultaneous fetches.
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     // Sub-classes can override this in order to do filtering of some sort.
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 }

Generated on Wed Dec 14 21:05:33 2005 for OpenMobileIS by  doxygen 1.4.4