protected void serveResource(final HttpServletRequest request, final HttpServletResponse response, final boolean content)
			throws IOException, ServletException {

		boolean serveContent = content;

		// Identify the requested resource path
		final String path = getRelativePath(request);
		if (log.isDebugEnabled()) {
			if (serveContent)
				log.debug("DefaultServlet.serveResource:  Serving resource '" + path + "' headers and data");
			else
				log.debug("DefaultServlet.serveResource:  Serving resource '" + path + "' headers only");
		}

		final CacheEntry cacheEntry = lookupCache(path);

		if (!cacheEntry.exists()) {
			// Check if we're included so we can return the appropriate
			// missing resource name in the error
			String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
			if (requestUri == null) {
				requestUri = request.getRequestURI();
			} else {
				// We're included
				// SRV.9.3 says we must throw a FNFE
				throw new FileNotFoundException("Missing resource : " + requestUri);
			}

			response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri);
			return;
		}

		// If the resource is not a collection, and the resource path
		// ends with "/" or "\", return NOT FOUND
		if (path.endsWith("/") || (path.endsWith("\\"))) {
			// Check if we're included so we can return the appropriate
			// missing resource name in the error
			String requestUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
			if (requestUri == null) {
				requestUri = request.getRequestURI();
			}
			response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri);
			return;
		}

		final boolean isError = response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST;

		// Check if the conditions specified in the optional If headers are
		// satisfied.

		// Checking If headers
		final boolean included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
		if (!included && !isError && !checkIfHeaders(request, response, cacheEntry.getAttributes())) {
			return;
		}

		// Find content type.
		String contentType = cacheEntry.getAttributes().getMimeType();
		if (contentType == null) {
			contentType = getServletContext().getMimeType(cacheEntry.getName());
			cacheEntry.getAttributes().setMimeType(contentType);
		}

		ArrayList<Range> ranges = null;
		long contentLength = -1L;

		if (!isError) {
			if (acceptsRanges()) {
				// Accept ranges header
				response.setHeader("Accept-Ranges", "bytes");
			}

			// Parse range specifier
			ranges = parseRange(request, response, cacheEntry.getAttributes());

			// ETag header
			response.setHeader("ETag", cacheEntry.getAttributes().getETag());

			// Last-Modified header
			response.setHeader("Last-Modified", cacheEntry.getAttributes().getLastModifiedHttp());
		}

		// Get content length
		contentLength = cacheEntry.getAttributes().getContentLength();
		// Special case for zero length files, which would cause a
		// (silent) ISE when setting the output buffer size
		if (contentLength == 0L) {
			serveContent = false;
		}

		ServletOutputStream ostream = null;
		PrintWriter writer = null;

		if (serveContent) {

			// Trying to retrieve the servlet output stream

			try {
				ostream = response.getOutputStream();
			} catch (final IllegalStateException e) {
				// If it fails, we try to get a Writer instead if we're
				// trying to serve a text file
				if ((contentType == null) || (contentType.startsWith("text")) || (contentType.endsWith("xml"))
						|| (contentType.contains("/javascript"))) {
					writer = response.getWriter();
					// Cannot reliably serve partial content with a Writer
					ranges = FULL;
				} else {
					throw e;
				}
			}

		}

		// Check to see if a Filter, Valve of wrapper has written some content.
		// If it has, disable range requests and setting of a content length
		// since neither can be done reliably.
		ServletResponse r = response;
		long contentWritten = 0;
		while (r instanceof ServletResponseWrapper) {
			r = ((ServletResponseWrapper) r).getResponse();
		}
		if (r instanceof ResponseFacade) {
			contentWritten = ((ResponseFacade) r).getContentWritten();
		}
		if (contentWritten > 0) {
			ranges = FULL;
		}

		if (isError || (((ranges == null) || (ranges.isEmpty())) && (request.getHeader("Range") == null)) || (ranges == FULL)) {

			// Set the appropriate output headers
			if (contentType != null) {
				if (log.isDebugEnabled())
					log.debug("DefaultServlet.serveFile:  contentType='" + contentType + "'");
				response.setContentType(contentType);
			}
			if ((cacheEntry.getResource() != null) && (contentLength >= 0) && (!serveContent || ostream != null)) {
				if (log.isDebugEnabled())
					log.debug("DefaultServlet.serveFile:  contentLength=" + contentLength);
				// Don't set a content length if something else has already
				// written to the response.
				if (contentWritten == 0) {
					if (contentLength < Integer.MAX_VALUE) {
						response.setContentLength((int) contentLength);
					} else {
						// Set the content-length as String to be able to use a
						// long
						response.setHeader("content-length", "" + contentLength);
					}
				}
			}

			final InputStream renderResult = null;

			// Copy the input stream to our output stream (if requested)
			if (serveContent) {
				try {
					response.setBufferSize(getOutputBufferSize());
				} catch (final IllegalStateException e) {
					// Silent catch
				}
				if (ostream != null) {
					copy(cacheEntry, renderResult, ostream);
				} else {
					copy(cacheEntry, renderResult, writer);
				}
			}

		} else {

			if ((ranges == null) || (ranges.isEmpty()))
				return;

			// Partial content response.

			response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

			if (ranges.size() == 1) {

				final Range range = ranges.get(0);
				response.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length);
				final long length = range.end - range.start + 1;
				if (length < Integer.MAX_VALUE) {
					response.setContentLength((int) length);
				} else {
					// Set the content-length as String to be able to use a long
					response.setHeader("content-length", "" + length);
				}

				if (contentType != null) {
					if (log.isDebugEnabled())
						log.debug("DefaultServlet.serveFile:  contentType='" + contentType + "'");
					response.setContentType(contentType);
				}

				if (serveContent) {
					try {
						response.setBufferSize(getOutputBufferSize());
					} catch (final IllegalStateException e) {
						// Silent catch
					}
					if (ostream != null) {
						copy(cacheEntry, ostream, range);
					} else {
						// we should not get here
						throw new IllegalStateException();
					}
				}

			} else {

				response.setContentType("multipart/byteranges; boundary=" + mimeSeparation);

				if (serveContent) {
					try {
						response.setBufferSize(getOutputBufferSize());
					} catch (final IllegalStateException e) {
						// Silent catch
					}
					if (ostream != null) {
						copy(cacheEntry, ostream, ranges.iterator(), contentType);
					} else {
						// we should not get here
						throw new IllegalStateException();
					}
				}

			}

		}

	}
protected void serveResource ( final HttpServletRequest request , final HttpServletResponse response , final boolean content ) throws IOException , ServletException { boolean serveContent = content ; final String path = getRelativePath ( request ) ; if ( log . isDebugEnabled ( ) ) { if ( serveContent ) log . debug ( "DefaultServlet.serveResource:  Serving resource '" + path + "' headers and data" ) ; else log . debug ( "DefaultServlet.serveResource:  Serving resource '" + path + "' headers only" ) ; } final CacheEntry cacheEntry = lookupCache ( path ) ; if ( ! cacheEntry . exists ( ) ) { String requestUri = ( String ) request . getAttribute ( RequestDispatcher . INCLUDE_REQUEST_URI ) ; if ( requestUri == null ) { requestUri = request . getRequestURI ( ) ; } else { throw new FileNotFoundException ( "Missing resource : " + requestUri ) ; } response . sendError ( HttpServletResponse . SC_NOT_FOUND , requestUri ) ; return ; } if ( path . endsWith ( "/" ) || ( path . endsWith ( "\\" ) ) ) { String requestUri = ( String ) request . getAttribute ( RequestDispatcher . INCLUDE_REQUEST_URI ) ; if ( requestUri == null ) { requestUri = request . getRequestURI ( ) ; } response . sendError ( HttpServletResponse . SC_NOT_FOUND , requestUri ) ; return ; } final boolean isError = response . getStatus ( ) >= HttpServletResponse . SC_BAD_REQUEST ; final boolean included = ( request . getAttribute ( RequestDispatcher . INCLUDE_CONTEXT_PATH ) != null ) ; if ( ! included && ! isError && ! checkIfHeaders ( request , response , cacheEntry . getAttributes ( ) ) ) { return ; } String contentType = cacheEntry . getAttributes ( ) . getMimeType ( ) ; if ( contentType == null ) { contentType = getServletContext ( ) . getMimeType ( cacheEntry . getName ( ) ) ; cacheEntry . getAttributes ( ) . setMimeType ( contentType ) ; } ArrayList < Range > ranges = null ; long contentLength = - 1L ; if ( ! isError ) { if ( acceptsRanges ( ) ) { response . setHeader ( "Accept-Ranges" , "bytes" ) ; } ranges = parseRange ( request , response , cacheEntry . getAttributes ( ) ) ; response . setHeader ( "ETag" , cacheEntry . getAttributes ( ) . getETag ( ) ) ; response . setHeader ( "Last-Modified" , cacheEntry . getAttributes ( ) . getLastModifiedHttp ( ) ) ; } contentLength = cacheEntry . getAttributes ( ) . getContentLength ( ) ; if ( contentLength == 0L ) { serveContent = false ; } ServletOutputStream ostream = null ; PrintWriter writer = null ; if ( serveContent ) { try { ostream = response . getOutputStream ( ) ; } catch ( final IllegalStateException e ) { if ( ( contentType == null ) || ( contentType . startsWith ( "text" ) ) || ( contentType . endsWith ( "xml" ) ) || ( contentType . contains ( "/javascript" ) ) ) { writer = response . getWriter ( ) ; ranges = FULL ; } else { throw e ; } } } ServletResponse r = response ; long contentWritten = 0 ; while ( r instanceof ServletResponseWrapper ) { r = ( ( ServletResponseWrapper ) r ) . getResponse ( ) ; } if ( r instanceof ResponseFacade ) { contentWritten = ( ( ResponseFacade ) r ) . getContentWritten ( ) ; } if ( contentWritten > 0 ) { ranges = FULL ; } if ( isError || ( ( ( ranges == null ) || ( ranges . isEmpty ( ) ) ) && ( request . getHeader ( "Range" ) == null ) ) || ( ranges == FULL ) ) { if ( contentType != null ) { if ( log . isDebugEnabled ( ) ) log . debug ( "DefaultServlet.serveFile:  contentType='" + contentType + "'" ) ; response . setContentType ( contentType ) ; } if ( ( cacheEntry . getResource ( ) != null ) && ( contentLength >= 0 ) && ( ! serveContent || ostream != null ) ) { if ( log . isDebugEnabled ( ) ) log . debug ( "DefaultServlet.serveFile:  contentLength=" + contentLength ) ; if ( contentWritten == 0 ) { if ( contentLength < Integer . MAX_VALUE ) { response . setContentLength ( ( int ) contentLength ) ; } else { response . setHeader ( "content-length" , "" + contentLength ) ; } } } final InputStream renderResult = null ; if ( serveContent ) { try { response . setBufferSize ( getOutputBufferSize ( ) ) ; } catch ( final IllegalStateException e ) { } if ( ostream != null ) { copy ( cacheEntry , renderResult , ostream ) ; } else { copy ( cacheEntry , renderResult , writer ) ; } } } else { if ( ( ranges == null ) || ( ranges . isEmpty ( ) ) ) return ; response . setStatus ( HttpServletResponse . SC_PARTIAL_CONTENT ) ; if ( ranges . size ( ) == 1 ) { final Range range = ranges . get ( 0 ) ; response . addHeader ( "Content-Range" , "bytes " + range . start + "-" + range . end + "/" + range . length ) ; final long length = range . end - range . start + 1 ; if ( length < Integer . MAX_VALUE ) { response . setContentLength ( ( int ) length ) ; } else { response . setHeader ( "content-length" , "" + length ) ; } if ( contentType != null ) { if ( log . isDebugEnabled ( ) ) log . debug ( "DefaultServlet.serveFile:  contentType='" + contentType + "'" ) ; response . setContentType ( contentType ) ; } if ( serveContent ) { try { response . setBufferSize ( getOutputBufferSize ( ) ) ; } catch ( final IllegalStateException e ) { } if ( ostream != null ) { copy ( cacheEntry , ostream , range ) ; } else { throw new IllegalStateException ( ) ; } } } else { response . setContentType ( "multipart/byteranges; boundary=" + mimeSeparation ) ; if ( serveContent ) { try { response . setBufferSize ( getOutputBufferSize ( ) ) ; } catch ( final IllegalStateException e ) { } if ( ostream != null ) { copy ( cacheEntry , ostream , ranges . iterator ( ) , contentType ) ; } else { throw new IllegalStateException ( ) ; } } } } }
Serve the specified resource, optionally including the data content.

@param request
The servlet request we are processing
@param response
The servlet response we are creating
@param content
Should the content be included?

@exception IOException
if an input/output error occurs
@exception ServletException
if a servlet-specified error occurs