Class AbstractFileServlet
- All Implemented Interfaces:
Serializable,javax.servlet.Servlet,javax.servlet.ServletConfig
- Direct Known Subclasses:
FileServlet
The well known "BalusC FileServlet", as an abstract template, slightly refactored, rewritten and modernized with a.o. fast NIO stuff instead of legacy RandomAccessFile. GZIP support is stripped off as that can be done application wide via GzipResponseFilter.
This servlet properly deals with ETag, If-None-Match and If-Modified-Since
caching requests, hereby improving browser caching. This servlet also properly deals with Range and
If-Range ranging requests (RFC7233), which is required
by most media players for proper audio/video streaming, and by webbrowsers and for a proper resume of an paused
download, and by download accelerators to be able to request smaller parts simultaneously. This servlet is ideal when
you have large files like media files placed outside the web application and you can't use the default servlet.
Usage
Just extend this class and override the getFile(HttpServletRequest) method to return the desired file. If
you want to trigger a HTTP 400 "Bad Request" error, simply throw IllegalArgumentException. If you want to
trigger a HTTP 404 "Not Found" error, simply return null, or a non-existent file.
Here's a concrete example which serves it via an URL like /media/foo.ext:
@WebServlet("/media/*")
public class MediaFileServlet extends FileServlet {
private File folder;
@Override
public void init() throws ServletException {
folder = new File("/var/webapp/media");
}
@Override
protected File getFile(HttpServletRequest request) {
String pathInfo = request.getPathInfo();
if (pathInfo == null || pathInfo.isEmpty() || "/".equals(pathInfo)) {
throw new IllegalArgumentException();
}
return new File(folder, pathInfo);
}
}
You can embed it in e.g. HTML5 video tag as below:
<video src="#{request.contextPath}/media/video.mp4" controls="controls" />
Customizing FileServlet
If more fine grained control is desired for handling "file not found" error, determining the cache expire time, the content type, whether the file should be supplied as an attachment and the attachment's file name, then the developer can opt to override one or more of the following protected methods:
handleFileNotFound(HttpServletRequest, HttpServletResponse)getExpireTime(HttpServletRequest, File)getContentType(HttpServletRequest, File)
See also:
- Since:
- 2.2
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classConvenience class for a byte range.protected classstatic classConvenience class for a file resource. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic <T> Tcoalesce(T... objects) Returns the first non-nullobject of the argument list, ornullif there is no such element.protected voiddoGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) protected voiddoHead(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) static StringURI-encode the given string using UTF-8.static StringURL-encode the given string using UTF-8.protected StringgetContentType(javax.servlet.http.HttpServletRequest request, File file) Returns the content type associated with the given HTTP servlet request and file.protected longgetExpireTime(javax.servlet.http.HttpServletRequest request, File file) Returns how long the resource may be cached by the client before it expires, in seconds.protected abstract FilegetFile(javax.servlet.http.HttpServletRequest request) Returns the file associated with the given HTTP servlet request.protected voidhandleFileNotFound(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) Handles the case when the file is not found.static voidsetCacheHeaders(javax.servlet.http.HttpServletResponse response, long expires) Set the cache headers.protected StringsetContentHeaders(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, AbstractFileServlet.Resource resource, List<AbstractFileServlet.Range> ranges) Set content headers.static voidsetNoCacheHeaders(javax.servlet.http.HttpServletResponse response) Set the no-cache headers.static booleanstartsWithOneOf(String string, String... prefixes) Returnstrueif the given string starts with one of the given prefixes.static longstream(File file, OutputStream output, long start, long length) Stream a specified range of the given file to the given output via NIOChannelsand a directly allocated NIOByteBuffer.static longstream(InputStream input, OutputStream output) Stream the given input to the given output via NIOChannelsand a directly allocated NIOByteBuffer.Methods inherited from class javax.servlet.http.HttpServlet
doDelete, doOptions, doPost, doPut, doTrace, getLastModified, service, serviceMethods inherited from class javax.servlet.GenericServlet
destroy, getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletInfo, getServletName, init, init, log, log
-
Constructor Details
-
AbstractFileServlet
public AbstractFileServlet()
-
-
Method Details
-
doHead
protected void doHead(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException - Overrides:
doHeadin classjavax.servlet.http.HttpServlet- Throws:
javax.servlet.ServletExceptionIOException
-
doGet
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException - Overrides:
doGetin classjavax.servlet.http.HttpServlet- Throws:
javax.servlet.ServletExceptionIOException
-
getFile
protected abstract File getFile(javax.servlet.http.HttpServletRequest request) throws IllegalArgumentException, AbstractFileServlet.RedirectException Returns the file associated with the given HTTP servlet request. If this method throwsIllegalArgumentException, then the servlet will return a HTTP 400 error. If this method returnsnull, or ifFile.isFile()returnsfalse, then the servlet will invokehandleFileNotFound(HttpServletRequest, HttpServletResponse).- Parameters:
request- The involved HTTP servlet request.- Returns:
- The file associated with the given HTTP servlet request.
- Throws:
IllegalArgumentException- When the request is mangled in such way that it's not recognizable as a valid file request. The servlet will then return a HTTP 400 error.AbstractFileServlet.RedirectException
-
handleFileNotFound
protected void handleFileNotFound(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws IOException Handles the case when the file is not found.The default implementation sends a HTTP 404 error.
- Parameters:
request- The involved HTTP servlet request.response- The involved HTTP servlet response.- Throws:
IOException- When something fails at I/O level.- Since:
- 2.3
-
getExpireTime
Returns how long the resource may be cached by the client before it expires, in seconds.The default implementation returns 30 days in seconds.
- Parameters:
request- The involved HTTP servlet request.file- The involved file.- Returns:
- The client cache expire time in seconds (not milliseconds!).
-
getContentType
Returns the content type associated with the given HTTP servlet request and file.The default implementation delegates
File.getName()toServletContext.getMimeType(String)with a fallback default value ofapplication/octet-stream.- Parameters:
request- The involved HTTP servlet request.file- The involved file.- Returns:
- The content type associated with the given HTTP servlet request and file.
-
setContentHeaders
protected String setContentHeaders(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, AbstractFileServlet.Resource resource, List<AbstractFileServlet.Range> ranges) Set content headers. -
encodeURI
URI-encode the given string using UTF-8. URIs (paths and filenames) have different encoding rules as compared to URL query string parameters.URLEncoderis actually only for www (HTML) form based query string parameter values (as used when a webbrowser submits a HTML form). URI encoding has a lot in common with URL encoding, but the space has to be %20 and some chars doesn't necessarily need to be encoded.- Parameters:
string- The string to be URI-encoded using UTF-8.- Returns:
- The given string, URI-encoded using UTF-8, or
nullifnullwas given. - Throws:
UnsupportedOperationException- When this platform does not support UTF-8.- Since:
- 2.4
-
encodeURL
URL-encode the given string using UTF-8.- Parameters:
string- The string to be URL-encoded using UTF-8.- Returns:
- The given string, URL-encoded using UTF-8, or
nullifnullwas given. - Throws:
UnsupportedOperationException- When this platform does not support UTF-8.- Since:
- 1.4
-
coalesce
Returns the first non-nullobject of the argument list, ornullif there is no such element.- Type Parameters:
T- The generic object type.- Parameters:
objects- The argument list of objects to be tested for non-null.- Returns:
- The first non-
nullobject of the argument list, ornullif there is no such element.
-
startsWithOneOf
Returnstrueif the given string starts with one of the given prefixes.- Parameters:
string- The object to be checked if it starts with one of the given prefixes.prefixes- The argument list of prefixes to be checked- Returns:
trueif the given string starts with one of the given prefixes.- Since:
- 1.4
-
stream
Stream the given input to the given output via NIOChannelsand a directly allocated NIOByteBuffer. Both the input and output streams will implicitly be closed after streaming, regardless of whether an exception is been thrown or not.- Parameters:
input- The input stream.output- The output stream.- Returns:
- The length of the written bytes.
- Throws:
IOException- When an I/O error occurs.
-
stream
public static long stream(File file, OutputStream output, long start, long length) throws IOException Stream a specified range of the given file to the given output via NIOChannelsand a directly allocated NIOByteBuffer. The output stream will only implicitly be closed after streaming when the specified range represents the whole file, regardless of whether an exception is been thrown or not.- Parameters:
file- The file.output- The output stream.start- The start position (offset).length- The (intented) length of written bytes.- Returns:
- The (actual) length of the written bytes. This may be smaller when the given length is too large.
- Throws:
IOException- When an I/O error occurs.- Since:
- 2.2
-
setCacheHeaders
public static void setCacheHeaders(javax.servlet.http.HttpServletResponse response, long expires) Set the cache headers. If the
expiresargument is larger than 0 seconds, then the following headers will be set:Cache-Control: public,max-age=[expiration time in seconds],must-revalidateExpires: [expiration date of now plus expiration time in seconds]
Else the method will delegate to
setNoCacheHeaders(HttpServletResponse).- Parameters:
response- The HTTP servlet response to set the headers on.expires- The expire time in seconds (not milliseconds!).- Since:
- 2.2
-
setNoCacheHeaders
public static void setNoCacheHeaders(javax.servlet.http.HttpServletResponse response) Set the no-cache headers. The following headers will be set:
Cache-Control: no-cache,no-store,must-revalidateExpires: [expiration date of 0]Pragma: no-cache
- Parameters:
response- The HTTP servlet response to set the headers on.- Since:
- 2.2
-