diff src/org/eclipse/jetty/server/handler/ResourceHandler.java @ 805:fc3e366caa51

add jetty-dir.css
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 22:46:38 -0600
parents 3428c60d7cfc
children 8e9db0bbf4f9
line wrap: on
line diff
--- a/src/org/eclipse/jetty/server/handler/ResourceHandler.java	Wed Sep 07 21:28:02 2016 -0600
+++ b/src/org/eclipse/jetty/server/handler/ResourceHandler.java	Wed Sep 07 22:46:38 2016 -0600
@@ -58,488 +58,488 @@
  */
 public class ResourceHandler extends HandlerWrapper
 {
-    private static final Logger LOG = Log.getLogger(ResourceHandler.class);
+	private static final Logger LOG = Log.getLogger(ResourceHandler.class);
 
-    ContextHandler _context;
-    Resource _baseResource;
-    Resource _defaultStylesheet;
-    Resource _stylesheet;
-    String[] _welcomeFiles={"index.html"};
-    MimeTypes _mimeTypes = new MimeTypes();
-    ByteArrayBuffer _cacheControl;
-    boolean _aliases;
-    boolean _directory;
-    boolean _etags;
+	ContextHandler _context;
+	Resource _baseResource;
+	Resource _defaultStylesheet;
+	Resource _stylesheet;
+	String[] _welcomeFiles={"index.html"};
+	MimeTypes _mimeTypes = new MimeTypes();
+	ByteArrayBuffer _cacheControl;
+	boolean _aliases;
+	boolean _directory;
+	boolean _etags;
 
-    /* ------------------------------------------------------------ */
-    public ResourceHandler()
-    {
-    	
-    }
+	/* ------------------------------------------------------------ */
+	public ResourceHandler()
+	{
+		
+	}
 
-    /* ------------------------------------------------------------ */
-    public MimeTypes getMimeTypes()
-    {
-        return _mimeTypes;
-    }
+	/* ------------------------------------------------------------ */
+	public MimeTypes getMimeTypes()
+	{
+		return _mimeTypes;
+	}
 
-    /* ------------------------------------------------------------ */
-    public void setMimeTypes(MimeTypes mimeTypes)
-    {
-        _mimeTypes = mimeTypes;
-    }
+	/* ------------------------------------------------------------ */
+	public void setMimeTypes(MimeTypes mimeTypes)
+	{
+		_mimeTypes = mimeTypes;
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return True if resource aliases are allowed.
-     */
-    public boolean isAliases()
-    {
-        return _aliases;
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return True if resource aliases are allowed.
+	 */
+	public boolean isAliases()
+	{
+		return _aliases;
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * Set if resource aliases (eg symlink, 8.3 names, case insensitivity) are allowed.
-     * Allowing aliases can significantly increase security vulnerabilities.
-     * If this handler is deployed inside a ContextHandler, then the
-     * {@link ContextHandler#isAliases()} takes precedent.
-     * @param aliases True if aliases are supported.
-     */
-    public void setAliases(boolean aliases)
-    {
-        _aliases = aliases;
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * Set if resource aliases (eg symlink, 8.3 names, case insensitivity) are allowed.
+	 * Allowing aliases can significantly increase security vulnerabilities.
+	 * If this handler is deployed inside a ContextHandler, then the
+	 * {@link ContextHandler#isAliases()} takes precedent.
+	 * @param aliases True if aliases are supported.
+	 */
+	public void setAliases(boolean aliases)
+	{
+		_aliases = aliases;
+	}
 
-    /* ------------------------------------------------------------ */
-    /** Get the directory option.
-     * @return true if directories are listed.
-     */
-    public boolean isDirectoriesListed()
-    {
-        return _directory;
-    }
+	/* ------------------------------------------------------------ */
+	/** Get the directory option.
+	 * @return true if directories are listed.
+	 */
+	public boolean isDirectoriesListed()
+	{
+		return _directory;
+	}
 
-    /* ------------------------------------------------------------ */
-    /** Set the directory.
-     * @param directory true if directories are listed.
-     */
-    public void setDirectoriesListed(boolean directory)
-    {
-        _directory = directory;
-    }
+	/* ------------------------------------------------------------ */
+	/** Set the directory.
+	 * @param directory true if directories are listed.
+	 */
+	public void setDirectoriesListed(boolean directory)
+	{
+		_directory = directory;
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return True if ETag processing is done
-     */
-    public boolean isEtags()
-    {
-        return _etags;
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return True if ETag processing is done
+	 */
+	public boolean isEtags()
+	{
+		return _etags;
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @param etags True if ETag processing is done
-     */
-    public void setEtags(boolean etags)
-    {
-        _etags = etags;
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param etags True if ETag processing is done
+	 */
+	public void setEtags(boolean etags)
+	{
+		_etags = etags;
+	}
 
-    /* ------------------------------------------------------------ */
-    @Override
-    public void doStart()
-    throws Exception
-    {
-        Context scontext = ContextHandler.getCurrentContext();
-        _context = (scontext==null?null:scontext.getContextHandler());
+	/* ------------------------------------------------------------ */
+	@Override
+	public void doStart()
+	throws Exception
+	{
+		Context scontext = ContextHandler.getCurrentContext();
+		_context = (scontext==null?null:scontext.getContextHandler());
 
-        if (_context!=null)
-            _aliases=_context.isAliases();
+		if (_context!=null)
+			_aliases=_context.isAliases();
 
-        if (!_aliases && !FileResource.getCheckAliases())
-            throw new IllegalStateException("Alias checking disabled");
+		if (!_aliases && !FileResource.getCheckAliases())
+			throw new IllegalStateException("Alias checking disabled");
 
-        super.doStart();
-    }
+		super.doStart();
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return Returns the resourceBase.
-     */
-    public Resource getBaseResource()
-    {
-        if (_baseResource==null)
-            return null;
-        return _baseResource;
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return Returns the resourceBase.
+	 */
+	public Resource getBaseResource()
+	{
+		if (_baseResource==null)
+			return null;
+		return _baseResource;
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return Returns the base resource as a string.
-     */
-    public String getResourceBase()
-    {
-        if (_baseResource==null)
-            return null;
-        return _baseResource.toString();
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return Returns the base resource as a string.
+	 */
+	public String getResourceBase()
+	{
+		if (_baseResource==null)
+			return null;
+		return _baseResource.toString();
+	}
 
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @param base The resourceBase to set.
-     */
-    public void setBaseResource(Resource base)
-    {
-        _baseResource=base;
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param base The resourceBase to set.
+	 */
+	public void setBaseResource(Resource base)
+	{
+		_baseResource=base;
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @param resourceBase The base resource as a string.
-     */
-    public void setResourceBase(String resourceBase)
-    {
-        try
-        {
-            setBaseResource(Resource.newResource(resourceBase));
-        }
-        catch (Exception e)
-        {
-            LOG.warn(e.toString());
-            LOG.debug(e);
-            throw new IllegalArgumentException(resourceBase);
-        }
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @return Returns the stylesheet as a Resource.
-     */
-    public Resource getStylesheet()
-    {
-    	if(_stylesheet != null)
-    	{
-    	    return _stylesheet;
-    	}
-    	else
-    	{
-    	    if(_defaultStylesheet == null)
-    	    {
-    	        try
-    	        {
-    	            _defaultStylesheet =  Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
-    	        }
-    	        catch(IOException e)
-    	        {
-    	            LOG.warn(e.toString());
-    	            LOG.debug(e);
-    	        }	 
-    	    }
-    	    return _defaultStylesheet;
-    	}
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param stylesheet The location of the stylesheet to be used as a String.
-     */
-    public void setStylesheet(String stylesheet)
-    {
-        try
-        {
-            _stylesheet = Resource.newResource(stylesheet);
-            if(!_stylesheet.exists())
-            {
-                LOG.warn("unable to find custom stylesheet: " + stylesheet);
-                _stylesheet = null;
-            }
-        }
-    	catch(Exception e)
-    	{
-    		LOG.warn(e.toString());
-            LOG.debug(e);
-            throw new IllegalArgumentException(stylesheet.toString());
-    	}
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param resourceBase The base resource as a string.
+	 */
+	public void setResourceBase(String resourceBase)
+	{
+		try
+		{
+			setBaseResource(Resource.newResource(resourceBase));
+		}
+		catch (Exception e)
+		{
+			LOG.warn(e.toString());
+			LOG.debug(e);
+			throw new IllegalArgumentException(resourceBase);
+		}
+	}
+	
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return Returns the stylesheet as a Resource.
+	 */
+	public Resource getStylesheet()
+	{
+		if(_stylesheet != null)
+		{
+			return _stylesheet;
+		}
+		else
+		{
+			if(_defaultStylesheet == null)
+			{
+				try
+				{
+					_defaultStylesheet =  Resource.newResource(this.getClass().getResource("/org/eclipse/jetty/jetty-dir.css"));
+				}
+				catch(IOException e)
+				{
+					LOG.warn(e.toString());
+					LOG.debug(e);
+				}	 
+			}
+			return _defaultStylesheet;
+		}
+	}
+	
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param stylesheet The location of the stylesheet to be used as a String.
+	 */
+	public void setStylesheet(String stylesheet)
+	{
+		try
+		{
+			_stylesheet = Resource.newResource(stylesheet);
+			if(!_stylesheet.exists())
+			{
+				LOG.warn("unable to find custom stylesheet: " + stylesheet);
+				_stylesheet = null;
+			}
+		}
+		catch(Exception e)
+		{
+			LOG.warn(e.toString());
+			LOG.debug(e);
+			throw new IllegalArgumentException(stylesheet.toString());
+		}
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return the cacheControl header to set on all static content.
-     */
-    public String getCacheControl()
-    {
-        return _cacheControl.toString();
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @return the cacheControl header to set on all static content.
+	 */
+	public String getCacheControl()
+	{
+		return _cacheControl.toString();
+	}
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @param cacheControl the cacheControl header to set on all static content.
-     */
-    public void setCacheControl(String cacheControl)
-    {
-        _cacheControl=cacheControl==null?null:new ByteArrayBuffer(cacheControl);
-    }
+	/* ------------------------------------------------------------ */
+	/**
+	 * @param cacheControl the cacheControl header to set on all static content.
+	 */
+	public void setCacheControl(String cacheControl)
+	{
+		_cacheControl=cacheControl==null?null:new ByteArrayBuffer(cacheControl);
+	}
 
-    /* ------------------------------------------------------------ */
-    /*
-     */
-    public Resource getResource(String path) throws MalformedURLException
-    {
-        if (path==null || !path.startsWith("/"))
-            throw new MalformedURLException(path);
+	/* ------------------------------------------------------------ */
+	/*
+	 */
+	public Resource getResource(String path) throws MalformedURLException
+	{
+		if (path==null || !path.startsWith("/"))
+			throw new MalformedURLException(path);
 
-        Resource base = _baseResource;
-        if (base==null)
-        {
-            if (_context==null)
-                return null;
-            base=_context.getBaseResource();
-            if (base==null)
-                return null;
-        }
+		Resource base = _baseResource;
+		if (base==null)
+		{
+			if (_context==null)
+				return null;
+			base=_context.getBaseResource();
+			if (base==null)
+				return null;
+		}
 
-        try
-        {
-            path=URIUtil.canonicalPath(path);
-            return base.addPath(path);
-        }
-        catch(Exception e)
-        {
-            LOG.ignore(e);
-        }
+		try
+		{
+			path=URIUtil.canonicalPath(path);
+			return base.addPath(path);
+		}
+		catch(Exception e)
+		{
+			LOG.ignore(e);
+		}
 
-        return null;
-    }
+		return null;
+	}
 
-    /* ------------------------------------------------------------ */
-    protected Resource getResource(HttpServletRequest request) throws MalformedURLException
-    {
-        String servletPath;
-        String pathInfo;
-        Boolean included = request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI) != null;
-        if (included != null && included.booleanValue())
-        {
-            servletPath = (String)request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH);
-            pathInfo = (String)request.getAttribute(Dispatcher.INCLUDE_PATH_INFO);
+	/* ------------------------------------------------------------ */
+	protected Resource getResource(HttpServletRequest request) throws MalformedURLException
+	{
+		String servletPath;
+		String pathInfo;
+		Boolean included = request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI) != null;
+		if (included != null && included.booleanValue())
+		{
+			servletPath = (String)request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH);
+			pathInfo = (String)request.getAttribute(Dispatcher.INCLUDE_PATH_INFO);
  
-            if (servletPath == null && pathInfo == null)
-            {
-                servletPath = request.getServletPath();
-                pathInfo = request.getPathInfo();
-            }
-        }
-        else
-        {
-            servletPath = request.getServletPath();
-            pathInfo = request.getPathInfo();
-        }
-        
-        String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
-        return getResource(pathInContext);
-    }
+			if (servletPath == null && pathInfo == null)
+			{
+				servletPath = request.getServletPath();
+				pathInfo = request.getPathInfo();
+			}
+		}
+		else
+		{
+			servletPath = request.getServletPath();
+			pathInfo = request.getPathInfo();
+		}
+		
+		String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
+		return getResource(pathInContext);
+	}
 
 
-    /* ------------------------------------------------------------ */
-    public String[] getWelcomeFiles()
-    {
-        return _welcomeFiles;
-    }
+	/* ------------------------------------------------------------ */
+	public String[] getWelcomeFiles()
+	{
+		return _welcomeFiles;
+	}
 
-    /* ------------------------------------------------------------ */
-    public void setWelcomeFiles(String[] welcomeFiles)
-    {
-        _welcomeFiles=welcomeFiles;
-    }
+	/* ------------------------------------------------------------ */
+	public void setWelcomeFiles(String[] welcomeFiles)
+	{
+		_welcomeFiles=welcomeFiles;
+	}
 
-    /* ------------------------------------------------------------ */
-    protected Resource getWelcome(Resource directory) throws MalformedURLException, IOException
-    {
-        for (int i=0;i<_welcomeFiles.length;i++)
-        {
-            Resource welcome=directory.addPath(_welcomeFiles[i]);
-            if (welcome.exists() && !welcome.isDirectory())
-                return welcome;
-        }
+	/* ------------------------------------------------------------ */
+	protected Resource getWelcome(Resource directory) throws MalformedURLException, IOException
+	{
+		for (int i=0;i<_welcomeFiles.length;i++)
+		{
+			Resource welcome=directory.addPath(_welcomeFiles[i]);
+			if (welcome.exists() && !welcome.isDirectory())
+				return welcome;
+		}
 
-        return null;
-    }
+		return null;
+	}
 
-    /* ------------------------------------------------------------ */
-    /*
-     * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
-     */
-    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-    {
-        if (baseRequest.isHandled())
-            return;
+	/* ------------------------------------------------------------ */
+	/*
+	 * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
+	 */
+	public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+	{
+		if (baseRequest.isHandled())
+			return;
 
-        boolean skipContentBody = false;
+		boolean skipContentBody = false;
 
-        if(!HttpMethods.GET.equals(request.getMethod()))
-        {
-            if(!HttpMethods.HEAD.equals(request.getMethod()))
-            {
-                //try another handler
-                super.handle(target, baseRequest, request, response);
-                return;
-            }
-            skipContentBody = true;
-        }
-        
-        Resource resource = getResource(request);
-        
-        if (resource==null || !resource.exists())
-        {
-            if (target.endsWith("/jetty-dir.css"))
-            {	                
-                resource = getStylesheet();
-                if (resource==null)
-                    return;
-                response.setContentType("text/css");
-            }
-            else 
-            {
-                //no resource - try other handlers
-                super.handle(target, baseRequest, request, response);
-                return;
-            }
-        }
-            
-        if (!_aliases && resource.getAlias()!=null)
-        {
-            LOG.info(resource+" aliased to "+resource.getAlias());
-            return;
-        }
+		if(!HttpMethods.GET.equals(request.getMethod()))
+		{
+			if(!HttpMethods.HEAD.equals(request.getMethod()))
+			{
+				//try another handler
+				super.handle(target, baseRequest, request, response);
+				return;
+			}
+			skipContentBody = true;
+		}
+		
+		Resource resource = getResource(request);
+		
+		if (resource==null || !resource.exists())
+		{
+			if (target.endsWith("/jetty-dir.css"))
+			{	                
+				resource = getStylesheet();
+				if (resource==null)
+					return;
+				response.setContentType("text/css");
+			}
+			else 
+			{
+				//no resource - try other handlers
+				super.handle(target, baseRequest, request, response);
+				return;
+			}
+		}
+			
+		if (!_aliases && resource.getAlias()!=null)
+		{
+			LOG.info(resource+" aliased to "+resource.getAlias());
+			return;
+		}
 
-        // We are going to serve something
-        baseRequest.setHandled(true);
+		// We are going to serve something
+		baseRequest.setHandled(true);
 
-        if (resource.isDirectory())
-        {
-            if (!request.getPathInfo().endsWith(URIUtil.SLASH))
-            {
-                response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)));
-                return;
-            }
+		if (resource.isDirectory())
+		{
+			if (!request.getPathInfo().endsWith(URIUtil.SLASH))
+			{
+				response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)));
+				return;
+			}
 
-            Resource welcome=getWelcome(resource);
-            if (welcome!=null && welcome.exists())
-                resource=welcome;
-            else
-            {
-                doDirectory(request,response,resource);
-                baseRequest.setHandled(true);
-                return;
-            }
-        }
+			Resource welcome=getWelcome(resource);
+			if (welcome!=null && welcome.exists())
+				resource=welcome;
+			else
+			{
+				doDirectory(request,response,resource);
+				baseRequest.setHandled(true);
+				return;
+			}
+		}
 
-        // set some headers
-        long last_modified=resource.lastModified();
-        String etag=null;
-        if (_etags)
-        {
-            // simple handling of only a single etag
-            String ifnm = request.getHeader(HttpHeaders.IF_NONE_MATCH);
-            etag=resource.getWeakETag();
-            if (ifnm!=null && resource!=null && ifnm.equals(etag))
-            {
-                response.setStatus(HttpStatus.NOT_MODIFIED_304);
-                baseRequest.getResponse().getHttpFields().put(HttpHeaders.ETAG_BUFFER,etag);
-                return;
-            }
-        }
-        
-        
-        if (last_modified>0)
-        {
-            long if_modified=request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
-            if (if_modified>0 && last_modified/1000<=if_modified/1000)
-            {
-                response.setStatus(HttpStatus.NOT_MODIFIED_304);
-                return;
-            }
-        }
+		// set some headers
+		long last_modified=resource.lastModified();
+		String etag=null;
+		if (_etags)
+		{
+			// simple handling of only a single etag
+			String ifnm = request.getHeader(HttpHeaders.IF_NONE_MATCH);
+			etag=resource.getWeakETag();
+			if (ifnm!=null && resource!=null && ifnm.equals(etag))
+			{
+				response.setStatus(HttpStatus.NOT_MODIFIED_304);
+				baseRequest.getResponse().getHttpFields().put(HttpHeaders.ETAG_BUFFER,etag);
+				return;
+			}
+		}
+		
+		
+		if (last_modified>0)
+		{
+			long if_modified=request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
+			if (if_modified>0 && last_modified/1000<=if_modified/1000)
+			{
+				response.setStatus(HttpStatus.NOT_MODIFIED_304);
+				return;
+			}
+		}
 
-        Buffer mime=_mimeTypes.getMimeByExtension(resource.toString());
-        if (mime==null)
-            mime=_mimeTypes.getMimeByExtension(request.getPathInfo());
+		Buffer mime=_mimeTypes.getMimeByExtension(resource.toString());
+		if (mime==null)
+			mime=_mimeTypes.getMimeByExtension(request.getPathInfo());
 
-        // set the headers
-        doResponseHeaders(response,resource,mime!=null?mime.toString():null);
-        response.setDateHeader(HttpHeaders.LAST_MODIFIED,last_modified);
-        if (_etags)
-            baseRequest.getResponse().getHttpFields().put(HttpHeaders.ETAG_BUFFER,etag);
-        
-        if(skipContentBody)
-            return;
-        // Send the content
-        OutputStream out =null;
-        try {out = response.getOutputStream();}
-        catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());}
+		// set the headers
+		doResponseHeaders(response,resource,mime!=null?mime.toString():null);
+		response.setDateHeader(HttpHeaders.LAST_MODIFIED,last_modified);
+		if (_etags)
+			baseRequest.getResponse().getHttpFields().put(HttpHeaders.ETAG_BUFFER,etag);
+		
+		if(skipContentBody)
+			return;
+		// Send the content
+		OutputStream out =null;
+		try {out = response.getOutputStream();}
+		catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());}
 
-        // See if a short direct method can be used?
-        if (out instanceof AbstractHttpConnection.Output)
-        {
-            // TODO file mapped buffers
-            ((AbstractHttpConnection.Output)out).sendContent(resource.getInputStream());
-        }
-        else
-        {
-            // Write content normally
-            resource.writeTo(out,0,resource.length());
-        }
-    }
+		// See if a short direct method can be used?
+		if (out instanceof AbstractHttpConnection.Output)
+		{
+			// TODO file mapped buffers
+			((AbstractHttpConnection.Output)out).sendContent(resource.getInputStream());
+		}
+		else
+		{
+			// Write content normally
+			resource.writeTo(out,0,resource.length());
+		}
+	}
 
-    /* ------------------------------------------------------------ */
-    protected void doDirectory(HttpServletRequest request,HttpServletResponse response, Resource resource)
-        throws IOException
-    {
-        if (_directory)
-        {
-            String listing = resource.getListHTML(request.getRequestURI(),request.getPathInfo().lastIndexOf("/") > 0);
-            response.setContentType("text/html; charset=UTF-8");
-            response.getWriter().println(listing);
-        }
-        else
-            response.sendError(HttpStatus.FORBIDDEN_403);
-    }
+	/* ------------------------------------------------------------ */
+	protected void doDirectory(HttpServletRequest request,HttpServletResponse response, Resource resource)
+		throws IOException
+	{
+		if (_directory)
+		{
+			String listing = resource.getListHTML(request.getRequestURI(),request.getPathInfo().lastIndexOf("/") > 0);
+			response.setContentType("text/html; charset=UTF-8");
+			response.getWriter().println(listing);
+		}
+		else
+			response.sendError(HttpStatus.FORBIDDEN_403);
+	}
 
-    /* ------------------------------------------------------------ */
-    /** Set the response headers.
-     * This method is called to set the response headers such as content type and content length.
-     * May be extended to add additional headers.
-     * @param response
-     * @param resource
-     * @param mimeType
-     */
-    protected void doResponseHeaders(HttpServletResponse response, Resource resource, String mimeType)
-    {
-        if (mimeType!=null)
-            response.setContentType(mimeType);
+	/* ------------------------------------------------------------ */
+	/** Set the response headers.
+	 * This method is called to set the response headers such as content type and content length.
+	 * May be extended to add additional headers.
+	 * @param response
+	 * @param resource
+	 * @param mimeType
+	 */
+	protected void doResponseHeaders(HttpServletResponse response, Resource resource, String mimeType)
+	{
+		if (mimeType!=null)
+			response.setContentType(mimeType);
 
-        long length=resource.length();
+		long length=resource.length();
 
-        if (response instanceof Response)
-        {
-            HttpFields fields = ((Response)response).getHttpFields();
+		if (response instanceof Response)
+		{
+			HttpFields fields = ((Response)response).getHttpFields();
 
-            if (length>0)
-                fields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER,length);
+			if (length>0)
+				fields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER,length);
 
-            if (_cacheControl!=null)
-                fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl);
-        }
-        else
-        {
-            if (length>0)
-                response.setHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(length));
+			if (_cacheControl!=null)
+				fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl);
+		}
+		else
+		{
+			if (length>0)
+				response.setHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(length));
 
-            if (_cacheControl!=null)
-                response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString());
-        }
+			if (_cacheControl!=null)
+				response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString());
+		}
 
-    }
+	}
 }