use of org.apache.catalina.WebResource in project tomcat by apache.
the class WebdavStatus method doPropfind.
/**
* PROPFIND Method.
* @param req The Servlet request
* @param resp The Servlet response
* @throws ServletException If an error occurs
* @throws IOException If an IO error occurs
*/
protected void doPropfind(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (!listings) {
// Get allowed methods
StringBuilder methodsAllowed = determineMethodsAllowed(req);
resp.addHeader("Allow", methodsAllowed.toString());
resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
return;
}
String path = getRelativePath(req);
if (path.length() > 1 && path.endsWith("/"))
path = path.substring(0, path.length() - 1);
// Properties which are to be displayed.
Vector<String> properties = null;
// Propfind depth
int depth = maxDepth;
// Propfind type
int type = FIND_ALL_PROP;
String depthStr = req.getHeader("Depth");
if (depthStr == null) {
depth = maxDepth;
} else {
if (depthStr.equals("0")) {
depth = 0;
} else if (depthStr.equals("1")) {
depth = 1;
} else if (depthStr.equals("infinity")) {
depth = maxDepth;
}
}
Node propNode = null;
if (req.getContentLengthLong() > 0) {
DocumentBuilder documentBuilder = getDocumentBuilder();
try {
Document document = documentBuilder.parse(new InputSource(req.getInputStream()));
// Get the root element of the document
Element rootElement = document.getDocumentElement();
NodeList childList = rootElement.getChildNodes();
for (int i = 0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch(currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
if (currentNode.getNodeName().endsWith("prop")) {
type = FIND_BY_PROPERTY;
propNode = currentNode;
}
if (currentNode.getNodeName().endsWith("propname")) {
type = FIND_PROPERTY_NAMES;
}
if (currentNode.getNodeName().endsWith("allprop")) {
type = FIND_ALL_PROP;
}
break;
}
}
} catch (SAXException e) {
// Something went wrong - bad request
resp.sendError(WebdavStatus.SC_BAD_REQUEST);
return;
} catch (IOException e) {
// Something went wrong - bad request
resp.sendError(WebdavStatus.SC_BAD_REQUEST);
return;
}
}
if (type == FIND_BY_PROPERTY) {
properties = new Vector<>();
// propNode must be non-null if type == FIND_BY_PROPERTY
@SuppressWarnings("null") NodeList childList = propNode.getChildNodes();
for (int i = 0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch(currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
String nodeName = currentNode.getNodeName();
String propertyName = null;
if (nodeName.indexOf(':') != -1) {
propertyName = nodeName.substring(nodeName.indexOf(':') + 1);
} else {
propertyName = nodeName;
}
// href is a live property which is handled differently
properties.addElement(propertyName);
break;
}
}
}
WebResource resource = resources.getResource(path);
if (!resource.exists()) {
int slash = path.lastIndexOf('/');
if (slash != -1) {
String parentPath = path.substring(0, slash);
Vector<String> currentLockNullResources = lockNullResources.get(parentPath);
if (currentLockNullResources != null) {
Enumeration<String> lockNullResourcesList = currentLockNullResources.elements();
while (lockNullResourcesList.hasMoreElements()) {
String lockNullPath = lockNullResourcesList.nextElement();
if (lockNullPath.equals(path)) {
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
resp.setContentType("text/xml; charset=UTF-8");
// Create multistatus object
XMLWriter generatedXML = new XMLWriter(resp.getWriter());
generatedXML.writeXMLHeader();
generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING);
parseLockNullProperties(req, generatedXML, lockNullPath, type, properties);
generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING);
generatedXML.sendData();
return;
}
}
}
}
}
if (!resource.exists()) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, path);
return;
}
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
resp.setContentType("text/xml; charset=UTF-8");
// Create multistatus object
XMLWriter generatedXML = new XMLWriter(resp.getWriter());
generatedXML.writeXMLHeader();
generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING);
if (depth == 0) {
parseProperties(req, generatedXML, path, type, properties);
} else {
// The stack always contains the object of the current level
Stack<String> stack = new Stack<>();
stack.push(path);
// Stack of the objects one level below
Stack<String> stackBelow = new Stack<>();
while ((!stack.isEmpty()) && (depth >= 0)) {
String currentPath = stack.pop();
parseProperties(req, generatedXML, currentPath, type, properties);
resource = resources.getResource(currentPath);
if (resource.isDirectory() && (depth > 0)) {
String[] entries = resources.list(currentPath);
for (String entry : entries) {
String newPath = currentPath;
if (!(newPath.endsWith("/")))
newPath += "/";
newPath += entry;
stackBelow.push(newPath);
}
// Displaying the lock-null resources present in that
// collection
String lockPath = currentPath;
if (lockPath.endsWith("/"))
lockPath = lockPath.substring(0, lockPath.length() - 1);
Vector<String> currentLockNullResources = lockNullResources.get(lockPath);
if (currentLockNullResources != null) {
Enumeration<String> lockNullResourcesList = currentLockNullResources.elements();
while (lockNullResourcesList.hasMoreElements()) {
String lockNullPath = lockNullResourcesList.nextElement();
parseLockNullProperties(req, generatedXML, lockNullPath, type, properties);
}
}
}
if (stack.isEmpty()) {
depth--;
stack = stackBelow;
stackBelow = new Stack<>();
}
generatedXML.sendData();
}
}
generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING);
generatedXML.sendData();
}
use of org.apache.catalina.WebResource in project tomcat by apache.
the class WebdavStatus method determineMethodsAllowed.
/**
* Determines the methods normally allowed for the resource.
* @param req The Servlet request
* @return a string builder with the allowed HTTP methods
*/
private StringBuilder determineMethodsAllowed(HttpServletRequest req) {
StringBuilder methodsAllowed = new StringBuilder();
WebResource resource = resources.getResource(getRelativePath(req));
if (!resource.exists()) {
methodsAllowed.append("OPTIONS, MKCOL, PUT, LOCK");
return methodsAllowed;
}
methodsAllowed.append("OPTIONS, GET, HEAD, POST, DELETE");
// Trace - assume disabled unless we can prove otherwise
if (req instanceof RequestFacade && ((RequestFacade) req).getAllowTrace()) {
methodsAllowed.append(", TRACE");
}
methodsAllowed.append(", PROPPATCH, COPY, MOVE, LOCK, UNLOCK");
if (listings) {
methodsAllowed.append(", PROPFIND");
}
if (resource.isFile()) {
methodsAllowed.append(", PUT");
}
return methodsAllowed;
}
use of org.apache.catalina.WebResource in project tomcat by apache.
the class WebdavStatus method copyResource.
/**
* Copy a resource.
*
* @param req Servlet request
* @param resp Servlet response
* @return boolean true if the copy is successful
* @throws IOException If an IO error occurs
*/
private boolean copyResource(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// Parsing destination header
String destinationPath = req.getHeader("Destination");
if (destinationPath == null) {
resp.sendError(WebdavStatus.SC_BAD_REQUEST);
return false;
}
// Remove url encoding from destination
destinationPath = UDecoder.URLDecode(destinationPath, "UTF8");
int protocolIndex = destinationPath.indexOf("://");
if (protocolIndex >= 0) {
// if the Destination URL contains the protocol, we can safely
// trim everything upto the first "/" character after "://"
int firstSeparator = destinationPath.indexOf('/', protocolIndex + 4);
if (firstSeparator < 0) {
destinationPath = "/";
} else {
destinationPath = destinationPath.substring(firstSeparator);
}
} else {
String hostName = req.getServerName();
if ((hostName != null) && (destinationPath.startsWith(hostName))) {
destinationPath = destinationPath.substring(hostName.length());
}
int portIndex = destinationPath.indexOf(':');
if (portIndex >= 0) {
destinationPath = destinationPath.substring(portIndex);
}
if (destinationPath.startsWith(":")) {
int firstSeparator = destinationPath.indexOf('/');
if (firstSeparator < 0) {
destinationPath = "/";
} else {
destinationPath = destinationPath.substring(firstSeparator);
}
}
}
// Normalise destination path (remove '.' and '..')
destinationPath = RequestUtil.normalize(destinationPath);
String contextPath = req.getContextPath();
if ((contextPath != null) && (destinationPath.startsWith(contextPath))) {
destinationPath = destinationPath.substring(contextPath.length());
}
String pathInfo = req.getPathInfo();
if (pathInfo != null) {
String servletPath = req.getServletPath();
if ((servletPath != null) && (destinationPath.startsWith(servletPath))) {
destinationPath = destinationPath.substring(servletPath.length());
}
}
if (debug > 0)
log("Dest path :" + destinationPath);
// Check destination path to protect special subdirectories
if (isSpecialPath(destinationPath)) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return false;
}
String path = getRelativePath(req);
if (destinationPath.equals(path)) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
return false;
}
// Parsing overwrite header
boolean overwrite = true;
String overwriteHeader = req.getHeader("Overwrite");
if (overwriteHeader != null) {
if (overwriteHeader.equalsIgnoreCase("T")) {
overwrite = true;
} else {
overwrite = false;
}
}
// Overwriting the destination
WebResource destination = resources.getResource(destinationPath);
if (overwrite) {
// Delete destination resource, if it exists
if (destination.exists()) {
if (!deleteResource(destinationPath, req, resp, true)) {
return false;
}
} else {
resp.setStatus(WebdavStatus.SC_CREATED);
}
} else {
// If the destination exists, then it's a conflict
if (destination.exists()) {
resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
return false;
}
}
// Copying source to destination
Hashtable<String, Integer> errorList = new Hashtable<>();
boolean result = copyResource(errorList, path, destinationPath);
if ((!result) || (!errorList.isEmpty())) {
if (errorList.size() == 1) {
resp.sendError(errorList.elements().nextElement().intValue());
} else {
sendReport(req, resp, errorList);
}
return false;
}
// Copy was successful
if (destination.exists()) {
resp.setStatus(WebdavStatus.SC_NO_CONTENT);
} else {
resp.setStatus(WebdavStatus.SC_CREATED);
}
// Removing any lock-null resource which would be present at
// the destination path
lockNullResources.remove(destinationPath);
return true;
}
use of org.apache.catalina.WebResource in project tomcat by apache.
the class DefaultServlet method renderHtml.
/**
* Return an InputStream to an HTML representation of the contents of this
* directory.
*
* @param contextPath Context path to which our internal paths are relative
* @param resource The associated resource
* @param encoding The encoding to use to process the readme (if any)
*
* @return the HTML data
*
* @throws IOException an IO error occurred
*/
protected InputStream renderHtml(String contextPath, WebResource resource, String encoding) throws IOException {
// Prepare a writer to a buffered area
ByteArrayOutputStream stream = new ByteArrayOutputStream();
OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8");
PrintWriter writer = new PrintWriter(osWriter);
StringBuilder sb = new StringBuilder();
String[] entries = resources.list(resource.getWebappPath());
// rewriteUrl(contextPath) is expensive. cache result for later reuse
String rewrittenContextPath = rewriteUrl(contextPath);
String directoryWebappPath = resource.getWebappPath();
// Render the page header
sb.append("<html>\r\n");
sb.append("<head>\r\n");
sb.append("<title>");
sb.append(sm.getString("directory.title", directoryWebappPath));
sb.append("</title>\r\n");
sb.append("<STYLE><!--");
sb.append(org.apache.catalina.util.TomcatCSS.TOMCAT_CSS);
sb.append("--></STYLE> ");
sb.append("</head>\r\n");
sb.append("<body>");
sb.append("<h1>");
sb.append(sm.getString("directory.title", directoryWebappPath));
// Render the link to our parent (if required)
String parentDirectory = directoryWebappPath;
if (parentDirectory.endsWith("/")) {
parentDirectory = parentDirectory.substring(0, parentDirectory.length() - 1);
}
int slash = parentDirectory.lastIndexOf('/');
if (slash >= 0) {
String parent = directoryWebappPath.substring(0, slash);
sb.append(" - <a href=\"");
sb.append(rewrittenContextPath);
if (parent.equals(""))
parent = "/";
sb.append(rewriteUrl(parent));
if (!parent.endsWith("/"))
sb.append("/");
sb.append("\">");
sb.append("<b>");
sb.append(sm.getString("directory.parent", parent));
sb.append("</b>");
sb.append("</a>");
}
sb.append("</h1>");
sb.append("<HR size=\"1\" noshade=\"noshade\">");
sb.append("<table width=\"100%\" cellspacing=\"0\"" + " cellpadding=\"5\" align=\"center\">\r\n");
// Render the column headings
sb.append("<tr>\r\n");
sb.append("<td align=\"left\"><font size=\"+1\"><strong>");
sb.append(sm.getString("directory.filename"));
sb.append("</strong></font></td>\r\n");
sb.append("<td align=\"center\"><font size=\"+1\"><strong>");
sb.append(sm.getString("directory.size"));
sb.append("</strong></font></td>\r\n");
sb.append("<td align=\"right\"><font size=\"+1\"><strong>");
sb.append(sm.getString("directory.lastModified"));
sb.append("</strong></font></td>\r\n");
sb.append("</tr>");
boolean shade = false;
for (String entry : entries) {
if (entry.equalsIgnoreCase("WEB-INF") || entry.equalsIgnoreCase("META-INF"))
continue;
WebResource childResource = resources.getResource(directoryWebappPath + entry);
if (!childResource.exists()) {
continue;
}
sb.append("<tr");
if (shade)
sb.append(" bgcolor=\"#eeeeee\"");
sb.append(">\r\n");
shade = !shade;
sb.append("<td align=\"left\"> \r\n");
sb.append("<a href=\"");
sb.append(rewrittenContextPath);
sb.append(rewriteUrl(directoryWebappPath + entry));
if (childResource.isDirectory())
sb.append("/");
sb.append("\"><tt>");
sb.append(RequestUtil.filter(entry));
if (childResource.isDirectory())
sb.append("/");
sb.append("</tt></a></td>\r\n");
sb.append("<td align=\"right\"><tt>");
if (childResource.isDirectory())
sb.append(" ");
else
sb.append(renderSize(childResource.getContentLength()));
sb.append("</tt></td>\r\n");
sb.append("<td align=\"right\"><tt>");
sb.append(childResource.getLastModifiedHttp());
sb.append("</tt></td>\r\n");
sb.append("</tr>\r\n");
}
// Render the page footer
sb.append("</table>\r\n");
sb.append("<HR size=\"1\" noshade=\"noshade\">");
String readme = getReadme(resource, encoding);
if (readme != null) {
sb.append(readme);
sb.append("<HR size=\"1\" noshade=\"noshade\">");
}
if (showServerInfo) {
sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>");
}
sb.append("</body>\r\n");
sb.append("</html>\r\n");
// Return an input stream to the underlying bytes
writer.write(sb.toString());
writer.flush();
return (new ByteArrayInputStream(stream.toByteArray()));
}
use of org.apache.catalina.WebResource in project tomcat by apache.
the class DefaultServlet method serveResource.
/**
* 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?
* @param encoding The encoding to use if it is necessary to access the
* source as characters rather than as bytes
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
protected void serveResource(HttpServletRequest request, HttpServletResponse response, boolean content, String encoding) throws IOException, ServletException {
boolean serveContent = content;
// Identify the requested resource path
String path = getRelativePath(request, true);
if (debug > 0) {
if (serveContent)
log("DefaultServlet.serveResource: Serving resource '" + path + "' headers and data");
else
log("DefaultServlet.serveResource: Serving resource '" + path + "' headers only");
}
if (path.length() == 0) {
// Context root redirect
doDirectoryRedirect(request, response);
return;
}
WebResource resource = resources.getResource(path);
if (!resource.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 {
// SRV.9.3 says we must throw a FNFE
throw new FileNotFoundException(sm.getString("defaultServlet.missingResource", requestUri));
}
response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri);
return;
}
if (!resource.canRead()) {
// 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 {
// reasonable
throw new FileNotFoundException(sm.getString("defaultServlet.missingResource", requestUri));
}
response.sendError(HttpServletResponse.SC_FORBIDDEN, requestUri);
return;
}
// ends with "/" or "\", return NOT FOUND
if (resource.isFile() && (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;
}
boolean isError = response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST;
boolean included = false;
// satisfied.
if (resource.isFile()) {
// Checking If headers
included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
if (!included && !isError && !checkIfHeaders(request, response, resource)) {
return;
}
}
// Find content type.
String contentType = resource.getMimeType();
if (contentType == null) {
contentType = getServletContext().getMimeType(resource.getName());
resource.setMimeType(contentType);
}
// These need to reflect the original resource, not the potentially
// precompressed version of the resource so get them now if they are going to
// be needed later
String eTag = null;
String lastModifiedHttp = null;
if (resource.isFile() && !isError) {
eTag = resource.getETag();
lastModifiedHttp = resource.getLastModifiedHttp();
}
// Serve a precompressed version of the file if present
boolean usingPrecompressedVersion = false;
if (compressionFormats.length > 0 && !included && resource.isFile() && !pathEndsWithCompressedExtension(path)) {
List<PrecompressedResource> precompressedResources = getAvailablePrecompressedResources(path);
if (!precompressedResources.isEmpty()) {
Collection<String> varyHeaders = response.getHeaders("Vary");
boolean addRequired = true;
for (String varyHeader : varyHeaders) {
if ("*".equals(varyHeader) || "accept-encoding".equalsIgnoreCase(varyHeader)) {
addRequired = false;
break;
}
}
if (addRequired) {
response.addHeader("Vary", "accept-encoding");
}
PrecompressedResource bestResource = getBestPrecompressedResource(request, precompressedResources);
if (bestResource != null) {
response.addHeader("Content-Encoding", bestResource.format.encoding);
resource = bestResource.resource;
usingPrecompressedVersion = true;
}
}
}
ArrayList<Range> ranges = null;
long contentLength = -1L;
if (resource.isDirectory()) {
if (!path.endsWith("/")) {
doDirectoryRedirect(request, response);
return;
}
// suppress them
if (!listings) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI());
return;
}
contentType = "text/html;charset=UTF-8";
} else {
if (!isError) {
if (useAcceptRanges) {
// Accept ranges header
response.setHeader("Accept-Ranges", "bytes");
}
// Parse range specifier
ranges = parseRange(request, response, resource);
// ETag header
response.setHeader("ETag", eTag);
// Last-Modified header
response.setHeader("Last-Modified", lastModifiedHttp);
}
// Get content length
contentLength = resource.getContentLength();
// (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 (IllegalStateException e) {
// trying to serve a text file
if (!usingPrecompressedVersion && ((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 (resource.isDirectory() || isError || ((ranges == null || ranges.isEmpty()) && request.getHeader("Range") == null) || ranges == FULL) {
// Set the appropriate output headers
if (contentType != null) {
if (debug > 0)
log("DefaultServlet.serveFile: contentType='" + contentType + "'");
response.setContentType(contentType);
}
if (resource.isFile() && contentLength >= 0 && (!serveContent || ostream != null)) {
if (debug > 0)
log("DefaultServlet.serveFile: contentLength=" + contentLength);
// written to the response.
if (contentWritten == 0) {
response.setContentLengthLong(contentLength);
}
}
if (serveContent) {
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
// Silent catch
}
InputStream renderResult = null;
if (ostream == null) {
// content directly.
if (resource.isDirectory()) {
renderResult = render(getPathPrefix(request), resource, encoding);
} else {
renderResult = resource.getInputStream();
}
copy(resource, renderResult, writer, encoding);
} else {
// Output is via an InputStream
if (resource.isDirectory()) {
renderResult = render(getPathPrefix(request), resource, encoding);
} else {
// Output is content of resource
if (!checkSendfile(request, response, resource, contentLength, null)) {
// sendfile not possible so check if resource
// content is available directly
byte[] resourceBody = resource.getContent();
if (resourceBody == null) {
// Resource content not available, use
// inputstream
renderResult = resource.getInputStream();
} else {
// Use the resource content directly
ostream.write(resourceBody);
}
}
}
// the output (this method closes the stream)
if (renderResult != null) {
copy(resource, renderResult, ostream);
}
}
}
} else {
if ((ranges == null) || (ranges.isEmpty()))
return;
// Partial content response.
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
if (ranges.size() == 1) {
Range range = ranges.get(0);
response.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length);
long length = range.end - range.start + 1;
response.setContentLengthLong(length);
if (contentType != null) {
if (debug > 0)
log("DefaultServlet.serveFile: contentType='" + contentType + "'");
response.setContentType(contentType);
}
if (serveContent) {
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
// Silent catch
}
if (ostream != null) {
if (!checkSendfile(request, response, resource, range.end - range.start + 1, range))
copy(resource, ostream, range);
} else {
// we should not get here
throw new IllegalStateException();
}
}
} else {
response.setContentType("multipart/byteranges; boundary=" + mimeSeparation);
if (serveContent) {
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
// Silent catch
}
if (ostream != null) {
copy(resource, ostream, ranges.iterator(), contentType);
} else {
// we should not get here
throw new IllegalStateException();
}
}
}
}
}
Aggregations