| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.server.handler; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.eclipse.jetty.http.HttpField; |
| import org.eclipse.jetty.http.HttpHeader; |
| import org.eclipse.jetty.http.HttpMethod; |
| import org.eclipse.jetty.http.MimeTypes; |
| import org.eclipse.jetty.http.PreEncodedHttpField; |
| import org.eclipse.jetty.server.Request; |
| import org.eclipse.jetty.server.ResourceContentFactory; |
| import org.eclipse.jetty.server.ResourceService; |
| import org.eclipse.jetty.server.handler.ContextHandler.Context; |
| import org.eclipse.jetty.util.URIUtil; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.util.resource.Resource; |
| import org.eclipse.jetty.util.resource.ResourceFactory; |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Resource Handler. |
| * |
| * This handle will serve static content and handle If-Modified-Since headers. No caching is done. Requests for resources that do not exist are let pass (Eg no |
| * 404's). |
| * |
| * |
| */ |
| public class ResourceHandler extends HandlerWrapper implements ResourceFactory |
| { |
| private static final Logger LOG = Log.getLogger(ResourceHandler.class); |
| |
| Resource _baseResource; |
| ContextHandler _context; |
| Resource _defaultStylesheet; |
| MimeTypes _mimeTypes; |
| private final ResourceService _resourceService; |
| Resource _stylesheet; |
| String[] _welcomes = |
| { "index.html" }; |
| |
| /* ------------------------------------------------------------ */ |
| public ResourceHandler() |
| { |
| _resourceService = new ResourceService() |
| { |
| @Override |
| protected String getWelcomeFile(String pathInContext) |
| { |
| if (_welcomes == null) |
| return null; |
| |
| String welcome_servlet = null; |
| for (int i = 0; i < _welcomes.length; i++) |
| { |
| String welcome_in_context = URIUtil.addPaths(pathInContext,_welcomes[i]); |
| Resource welcome = getResource(welcome_in_context); |
| if (welcome != null && welcome.exists()) |
| return _welcomes[i]; |
| } |
| return welcome_servlet; |
| } |
| |
| @Override |
| protected void notFound(HttpServletRequest request, HttpServletResponse response) throws IOException |
| { |
| } |
| }; |
| _resourceService.setGzipEquivalentFileExtensions(new ArrayList<>(Arrays.asList(new String[] |
| { ".svgz" }))); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public void doStart() throws Exception |
| { |
| Context scontext = ContextHandler.getCurrentContext(); |
| _context = (scontext == null?null:scontext.getContextHandler()); |
| _mimeTypes = _context == null?new MimeTypes():_context.getMimeTypes(); |
| |
| _resourceService.setContentFactory(new ResourceContentFactory(this,_mimeTypes,_resourceService.isGzip())); |
| |
| super.doStart(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return Returns the resourceBase. |
| */ |
| public Resource getBaseResource() |
| { |
| if (_baseResource == null) |
| return null; |
| return _baseResource; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return the cacheControl header to set on all static content. |
| */ |
| public String getCacheControl() |
| { |
| return _resourceService.getCacheControl().getValue(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return file extensions that signify that a file is gzip compressed. Eg ".svgz" |
| */ |
| public List<String> getGzipEquivalentFileExtensions() |
| { |
| return _resourceService.getGzipEquivalentFileExtensions(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public MimeTypes getMimeTypes() |
| { |
| return _mimeTypes; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Get the minimum content length for async handling. |
| * |
| * @return The minimum size in bytes of the content before asynchronous handling is used, or -1 for no async handling or 0 (default) for using |
| * {@link HttpServletResponse#getBufferSize()} as the minimum length. |
| */ |
| @Deprecated |
| public int getMinAsyncContentLength() |
| { |
| return -1; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Get minimum memory mapped file content length. |
| * |
| * @return the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 (default) for no memory mapped buffers. |
| */ |
| @Deprecated |
| public int getMinMemoryMappedContentLength() |
| { |
| return -1; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /* |
| */ |
| @Override |
| public Resource getResource(String path) |
| { |
| if (LOG.isDebugEnabled()) |
| LOG.debug("{} getResource({})",_context == null?_baseResource:_context,_baseResource,path); |
| |
| if (path == null || !path.startsWith("/")) |
| return null; |
| |
| try |
| { |
| Resource r = null; |
| |
| if (_baseResource != null) |
| { |
| path = URIUtil.canonicalPath(path); |
| r = _baseResource.addPath(path); |
| |
| if (r != null && r.isAlias() && (_context == null || !_context.checkAlias(path,r))) |
| { |
| if (LOG.isDebugEnabled()) |
| LOG.debug("resource={} alias={}",r,r.getAlias()); |
| return null; |
| } |
| } |
| else if (_context != null) |
| r = _context.getResource(path); |
| |
| if ((r == null || !r.exists()) && path.endsWith("/jetty-dir.css")) |
| r = getStylesheet(); |
| |
| return r; |
| } |
| catch (Exception e) |
| { |
| LOG.debug(e); |
| } |
| |
| return null; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return Returns the base resource as a string. |
| */ |
| public String getResourceBase() |
| { |
| if (_baseResource == null) |
| return null; |
| return _baseResource.toString(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return Returns the stylesheet as a Resource. |
| */ |
| public Resource getStylesheet() |
| { |
| if (_stylesheet != null) |
| { |
| return _stylesheet; |
| } |
| else |
| { |
| if (_defaultStylesheet == null) |
| { |
| _defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-dir.css")); |
| } |
| return _defaultStylesheet; |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String[] getWelcomeFiles() |
| { |
| return _welcomes; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /* |
| * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int) |
| */ |
| @Override |
| public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| { |
| if (baseRequest.isHandled()) |
| return; |
| |
| if (!HttpMethod.GET.is(request.getMethod())) |
| { |
| if (!HttpMethod.HEAD.is(request.getMethod())) |
| { |
| // try another handler |
| super.handle(target,baseRequest,request,response); |
| return; |
| } |
| } |
| |
| _resourceService.doGet(request,response); |
| |
| if (response.isCommitted()) |
| baseRequest.setHandled(true); |
| else |
| // no resource - try other handlers |
| super.handle(target,baseRequest,request,response); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return If true, range requests and responses are supported |
| */ |
| public boolean isAcceptRanges() |
| { |
| return _resourceService.isAcceptRanges(); |
| } |
| |
| /** |
| * @return If true, directory listings are returned if no welcome file is found. Else 403 Forbidden. |
| */ |
| public boolean isDirAllowed() |
| { |
| return _resourceService.isDirAllowed(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Get the directory option. |
| * |
| * @return true if directories are listed. |
| */ |
| public boolean isDirectoriesListed() |
| { |
| return _resourceService.isDirAllowed(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return True if ETag processing is done |
| */ |
| public boolean isEtags() |
| { |
| return _resourceService.isEtags(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return If set to true, then static content will be served as gzip content encoded if a matching resource is found ending with ".gz" |
| */ |
| public boolean isGzip() |
| { |
| return _resourceService.isGzip(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return true, only the path info will be applied to the resourceBase |
| */ |
| public boolean isPathInfoOnly() |
| { |
| return _resourceService.isPathInfoOnly(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return If true, welcome files are redirected rather than forwarded to. |
| */ |
| public boolean isRedirectWelcome() |
| { |
| return _resourceService.isRedirectWelcome(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param acceptRanges If true, range requests and responses are supported |
| */ |
| public void setAcceptRanges(boolean acceptRanges) |
| { |
| _resourceService.setAcceptRanges(acceptRanges); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param base The resourceBase to server content from. If null the |
| * context resource base is used. |
| */ |
| public void setBaseResource(Resource base) |
| { |
| _baseResource = base; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param cacheControl |
| * the cacheControl header to set on all static content. |
| */ |
| public void setCacheControl(String cacheControl) |
| { |
| _resourceService.setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL,cacheControl)); |
| } |
| |
| /** |
| * @param dirAllowed |
| * If true, directory listings are returned if no welcome file is found. Else 403 Forbidden. |
| */ |
| public void setDirAllowed(boolean dirAllowed) |
| { |
| _resourceService.setDirAllowed(dirAllowed); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set the directory. |
| * |
| * @param directory |
| * true if directories are listed. |
| */ |
| public void setDirectoriesListed(boolean directory) |
| { |
| _resourceService.setDirAllowed(directory); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param etags |
| * True if ETag processing is done |
| */ |
| public void setEtags(boolean etags) |
| { |
| _resourceService.setEtags(etags); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param gzip |
| * If set to true, then static content will be served as gzip content encoded if a matching resource is found ending with ".gz" |
| */ |
| public void setGzip(boolean gzip) |
| { |
| _resourceService.setGzip(gzip); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param gzipEquivalentFileExtensions file extensions that signify that a file is gzip compressed. Eg ".svgz" |
| */ |
| public void setGzipEquivalentFileExtensions(List<String> gzipEquivalentFileExtensions) |
| { |
| _resourceService.setGzipEquivalentFileExtensions(gzipEquivalentFileExtensions); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setMimeTypes(MimeTypes mimeTypes) |
| { |
| _mimeTypes = mimeTypes; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set the minimum content length for async handling. |
| * |
| * @param minAsyncContentLength |
| * The minimum size in bytes of the content before asynchronous handling is used, or -1 for no async handling or 0 for using |
| * {@link HttpServletResponse#getBufferSize()} as the minimum length. |
| */ |
| @Deprecated |
| public void setMinAsyncContentLength(int minAsyncContentLength) |
| { |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set minimum memory mapped file content length. |
| * |
| * @param minMemoryMappedFileSize |
| * the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 for no memory mapped buffers. |
| */ |
| @Deprecated |
| public void setMinMemoryMappedContentLength(int minMemoryMappedFileSize) |
| { |
| } |
| |
| /** |
| * @param pathInfoOnly |
| * true, only the path info will be applied to the resourceBase |
| */ |
| public void setPathInfoOnly(boolean pathInfoOnly) |
| { |
| _resourceService.setPathInfoOnly(pathInfoOnly); |
| } |
| |
| /** |
| * @param redirectWelcome |
| * If true, welcome files are redirected rather than forwarded to. |
| */ |
| public void setRedirectWelcome(boolean redirectWelcome) |
| { |
| _resourceService.setRedirectWelcome(redirectWelcome); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @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); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @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); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setWelcomeFiles(String[] welcomeFiles) |
| { |
| _welcomes = welcomeFiles; |
| } |
| |
| } |