mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Integrated fix for ALF-11777 so that locks are not kept for more than 24 hours and 24 hour or infinite locks are dropped on user's session destruction. Extracted interface from WebDAVLockService and moved the implementation to WebDAVLockServiceImpl. Modified WebDAVLockServiceImpl to use the LockStore in-memory locking. WebDAV and SPP use WebDAVLockService instead of directly using LockStore. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@35486 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
841 lines
28 KiB
Java
841 lines
28 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.repo.webdav;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.net.InetAddress;
|
|
import java.net.MalformedURLException;
|
|
import java.net.NetworkInterface;
|
|
import java.net.URL;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.StringTokenizer;
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
import org.alfresco.jlan.util.IPAddress;
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.tenant.TenantService;
|
|
import org.alfresco.service.ServiceRegistry;
|
|
import org.alfresco.service.cmr.action.ActionService;
|
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
|
import org.alfresco.service.cmr.model.FileFolderService;
|
|
import org.alfresco.service.cmr.model.FileInfo;
|
|
import org.alfresco.service.cmr.model.FileNotFoundException;
|
|
import org.alfresco.service.cmr.repository.CopyService;
|
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
|
import org.alfresco.service.cmr.search.SearchService;
|
|
import org.alfresco.service.cmr.security.AuthenticationService;
|
|
import org.alfresco.service.cmr.security.PermissionService;
|
|
import org.alfresco.service.cmr.site.SiteInfo;
|
|
import org.alfresco.service.cmr.site.SiteService;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.util.EqualsHelper;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.springframework.extensions.surf.util.URLDecoder;
|
|
import org.springframework.extensions.surf.util.URLEncoder;
|
|
import org.xml.sax.helpers.AttributesImpl;
|
|
|
|
/**
|
|
* WebDAV Protocol Helper Class
|
|
*
|
|
* <p>Provides helper methods for repository access using the WebDAV protocol.
|
|
*
|
|
* @author GKSpencer
|
|
*/
|
|
public class WebDAVHelper
|
|
{
|
|
// Constants
|
|
private static final String HTTPS_SCHEME = "https://";
|
|
private static final String HTTP_SCHEME = "http://";
|
|
|
|
// Path seperator
|
|
public static final String PathSeperator = "/";
|
|
public static final char PathSeperatorChar = '/';
|
|
public static final String EMPTY_SITE_ID = "";
|
|
|
|
// Logging
|
|
private static Log logger = LogFactory.getLog("org.alfresco.webdav.protocol");
|
|
|
|
// Service registry
|
|
private ServiceRegistry m_serviceRegistry;
|
|
|
|
// Services
|
|
private NodeService m_nodeService;
|
|
private FileFolderService m_fileFolderService;
|
|
private SearchService m_searchService;
|
|
private NamespaceService m_namespaceService;
|
|
private DictionaryService m_dictionaryService;
|
|
private MimetypeService m_mimetypeService;
|
|
private WebDAVLockService m_lockService;
|
|
private ActionService m_actionService;
|
|
private AuthenticationService m_authService;
|
|
private PermissionService m_permissionService;
|
|
private TenantService m_tenantService;
|
|
|
|
// Empty XML attribute list
|
|
|
|
private AttributesImpl m_nullAttribs = new AttributesImpl();
|
|
|
|
/**
|
|
* Class constructor
|
|
*/
|
|
protected WebDAVHelper(ServiceRegistry serviceRegistry, AuthenticationService authService, TenantService tenantService)
|
|
{
|
|
m_serviceRegistry = serviceRegistry;
|
|
|
|
m_nodeService = m_serviceRegistry.getNodeService();
|
|
m_fileFolderService = m_serviceRegistry.getFileFolderService();
|
|
m_searchService = m_serviceRegistry.getSearchService();
|
|
m_namespaceService = m_serviceRegistry.getNamespaceService();
|
|
m_dictionaryService = m_serviceRegistry.getDictionaryService();
|
|
m_mimetypeService = m_serviceRegistry.getMimetypeService();
|
|
m_lockService = (WebDAVLockService)m_serviceRegistry.getService(QName.createQName(NamespaceService.ALFRESCO_URI, WebDAVLockService.BEAN_NAME));
|
|
m_actionService = m_serviceRegistry.getActionService();
|
|
m_permissionService = m_serviceRegistry.getPermissionService();
|
|
m_tenantService = tenantService;
|
|
m_authService = authService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the authentication service
|
|
*/
|
|
public final AuthenticationService getAuthenticationService()
|
|
{
|
|
return m_authService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the service registry
|
|
*/
|
|
public final ServiceRegistry getServiceRegistry()
|
|
{
|
|
return m_serviceRegistry;
|
|
}
|
|
|
|
/**
|
|
* @return Return the node service
|
|
*/
|
|
public final NodeService getNodeService()
|
|
{
|
|
return m_nodeService;
|
|
}
|
|
|
|
public FileFolderService getFileFolderService()
|
|
{
|
|
return m_fileFolderService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the search service
|
|
*/
|
|
public final SearchService getSearchService()
|
|
{
|
|
return m_searchService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the namespace service
|
|
*/
|
|
public final NamespaceService getNamespaceService()
|
|
{
|
|
return m_namespaceService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the dictionary service
|
|
*/
|
|
public final DictionaryService getDictionaryService()
|
|
{
|
|
return m_dictionaryService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the mimetype service
|
|
*/
|
|
public final MimetypeService getMimetypeService()
|
|
{
|
|
return m_mimetypeService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the lock service
|
|
*/
|
|
public final WebDAVLockService getLockService()
|
|
{
|
|
return m_lockService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the action service
|
|
*/
|
|
public final ActionService getActionService()
|
|
{
|
|
return m_actionService;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return Return the permission service
|
|
*/
|
|
public final PermissionService getPermissionService()
|
|
{
|
|
return m_permissionService;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the {@link TenantService} held by the helper.
|
|
*
|
|
* @return TenantService
|
|
*/
|
|
public TenantService getTenantService()
|
|
{
|
|
return m_tenantService;
|
|
}
|
|
|
|
/**
|
|
* @return Return the copy service
|
|
*/
|
|
public final CopyService getCopyService()
|
|
{
|
|
return getServiceRegistry().getCopyService();
|
|
}
|
|
|
|
/**
|
|
* Split the path into seperate directory path and file name strings.
|
|
* If the path is not empty, then there will always be an entry for the filename
|
|
*
|
|
* @param path Full path string.
|
|
* @return Returns a String[2] with the folder path and file path.
|
|
*/
|
|
public final String[] splitPath(String path)
|
|
{
|
|
if (path == null)
|
|
throw new IllegalArgumentException("path may not be null");
|
|
|
|
// Create an array of strings to hold the path and file name strings
|
|
String[] pathStr = new String[] {"", ""};
|
|
|
|
// Check if the path has a trailing seperator, if so then there is no file name.
|
|
|
|
int pos = path.lastIndexOf(PathSeperatorChar);
|
|
if (pos == -1 || pos == (path.length() - 1))
|
|
{
|
|
// Set the path string in the returned string array
|
|
pathStr[1] = path;
|
|
}
|
|
else
|
|
{
|
|
pathStr[0] = path.substring(0, pos);
|
|
pathStr[1] = path.substring(pos + 1);
|
|
}
|
|
// Return the path strings
|
|
return pathStr;
|
|
}
|
|
|
|
/**
|
|
* Split the path into all the component directories and filename
|
|
*
|
|
* @param path the string to split
|
|
* @return an array of all the path components
|
|
*/
|
|
public final List<String> splitAllPaths(String path)
|
|
{
|
|
if (path == null || path.length() == 0)
|
|
{
|
|
return Collections.emptyList();
|
|
}
|
|
|
|
// split the path
|
|
StringTokenizer token = new StringTokenizer(path, PathSeperator);
|
|
List<String> results = new ArrayList<String>(10);
|
|
while (token.hasMoreTokens())
|
|
{
|
|
results.add(token.nextToken());
|
|
}
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Get the file info for the given paths
|
|
*
|
|
* @param rootNodeRef the acting webdav root
|
|
* @param path the path to search for
|
|
* @param servletPath the base servlet path, which may be null or empty
|
|
* @return Return the file info for the path
|
|
* @throws FileNotFoundException
|
|
* if the path doesn't refer to a valid node
|
|
*/
|
|
public final FileInfo getNodeForPath(NodeRef rootNodeRef, String path, String servletPath) throws FileNotFoundException
|
|
{
|
|
if (rootNodeRef == null)
|
|
{
|
|
throw new IllegalArgumentException("Root node may not be null");
|
|
}
|
|
else if (path == null)
|
|
{
|
|
throw new IllegalArgumentException("Path may not be null");
|
|
}
|
|
|
|
FileFolderService fileFolderService = getFileFolderService();
|
|
// Check for the root path
|
|
if ( path.length() == 0 || path.equals(PathSeperator) || EqualsHelper.nullSafeEquals(path, servletPath))
|
|
{
|
|
return fileFolderService.getFileInfo(rootNodeRef);
|
|
}
|
|
|
|
// Remove the servlet path from the path, assuming it hasn't already been done
|
|
if (servletPath != null && servletPath.length() > 0)
|
|
{
|
|
// Need to ensure we don't strip /alfresco from a site of /alfresco_name/
|
|
String comparePath = servletPath + "/";
|
|
if (path.startsWith(comparePath))
|
|
{
|
|
// Strip the servlet path from the relative path
|
|
path = path.substring(servletPath.length());
|
|
}
|
|
}
|
|
|
|
// split the paths up
|
|
List<String> splitPath = splitAllPaths(path);
|
|
|
|
// find it
|
|
FileInfo fileInfo = m_fileFolderService.resolveNamePath(rootNodeRef, splitPath);
|
|
|
|
// done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Fetched node for path: \n" +
|
|
" root: " + rootNodeRef + "\n" +
|
|
" path: " + path + "\n" +
|
|
" servlet path: " + servletPath + "\n" +
|
|
" result: " + fileInfo);
|
|
}
|
|
return fileInfo;
|
|
}
|
|
|
|
public final FileInfo getParentNodeForPath(NodeRef rootNodeRef, String path, String servletPath) throws FileNotFoundException
|
|
{
|
|
if (rootNodeRef == null)
|
|
{
|
|
throw new IllegalArgumentException("Root node may not be null");
|
|
}
|
|
else if (path == null)
|
|
{
|
|
throw new IllegalArgumentException("Path may not be null");
|
|
}
|
|
// shorten the path
|
|
String[] paths = splitPath(path);
|
|
return getNodeForPath(rootNodeRef, paths[0], servletPath);
|
|
}
|
|
|
|
/**
|
|
* Return the relative path for the node walking back to the specified root node
|
|
*
|
|
* @param rootNodeRef the root below which the path will be valid
|
|
* @param nodeRef the node's path to get
|
|
* @return Returns string of form <b>/A/B/C</b> where C represents the from node and
|
|
*/
|
|
public final String getPathFromNode(NodeRef rootNodeRef, NodeRef nodeRef) throws FileNotFoundException
|
|
{
|
|
// Check if the nodes are valid, or equal
|
|
if (rootNodeRef == null || nodeRef == null)
|
|
throw new IllegalArgumentException("Invalid node(s) in getPathFromNode call");
|
|
|
|
// short cut if the path node is the root node
|
|
if (rootNodeRef.equals(nodeRef))
|
|
return "";
|
|
|
|
FileFolderService fileFolderService = getFileFolderService();
|
|
|
|
// get the path elements
|
|
List<FileInfo> pathInfos = fileFolderService.getNamePath(rootNodeRef, nodeRef);
|
|
|
|
// build the path string
|
|
StringBuilder sb = new StringBuilder(pathInfos.size() * 20);
|
|
for (FileInfo fileInfo : pathInfos)
|
|
{
|
|
sb.append(WebDAVHelper.PathSeperatorChar);
|
|
sb.append(fileInfo.getName());
|
|
}
|
|
// done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Build name path for node: \n" +
|
|
" root: " + rootNodeRef + "\n" +
|
|
" target: " + nodeRef + "\n" +
|
|
" path: " + sb);
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Make an ETag value for a node using the GUID and modify date/time
|
|
*/
|
|
public final String makeETag(FileInfo nodeInfo)
|
|
{
|
|
// Get the modify date/time property for the node
|
|
|
|
StringBuilder etag = new StringBuilder();
|
|
makeETagString(nodeInfo, etag);
|
|
return etag.toString();
|
|
}
|
|
|
|
/**
|
|
* Make an ETag value for a node using the GUID and modify date/time
|
|
*/
|
|
public final String makeQuotedETag(FileInfo nodeInfo)
|
|
{
|
|
StringBuilder etag = new StringBuilder();
|
|
|
|
etag.append("\"");
|
|
makeETagString(nodeInfo, etag);
|
|
etag.append("\"");
|
|
return etag.toString();
|
|
}
|
|
|
|
/**
|
|
* Make an ETag value for a node using the GUID and modify date/time
|
|
*/
|
|
protected final void makeETagString(FileInfo nodeInfo, StringBuilder etag)
|
|
{
|
|
// Get the modify date/time property for the node
|
|
|
|
Object modVal = nodeInfo.getProperties().get(ContentModel.PROP_MODIFIED);
|
|
|
|
etag.append(nodeInfo.getNodeRef().getId());
|
|
|
|
if ( modVal != null)
|
|
{
|
|
etag.append("_");
|
|
etag.append(DefaultTypeConverter.INSTANCE.longValue(modVal));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return Return the null XML attribute list
|
|
*/
|
|
public final AttributesImpl getNullAttributes()
|
|
{
|
|
return m_nullAttribs;
|
|
}
|
|
|
|
/**
|
|
* Encodes the given string to valid URL format
|
|
*
|
|
* @param s the String to convert
|
|
*/
|
|
public final static String encodeURL(String s)
|
|
{
|
|
return encodeURL(s, null);
|
|
}
|
|
|
|
public final static String encodeURL(String s, String userAgent)
|
|
{
|
|
try
|
|
{
|
|
if (userAgent != null && (userAgent.startsWith(WebDAV.AGENT_MICROSOFT_DATA_ACCESS_INTERNET_PUBLISHING_PROVIDER_DAV)
|
|
|| userAgent.contains(WebDAV.AGENT_INTERNET_EXPLORER)))
|
|
{
|
|
return encodeUrlReservedSymbols(s);
|
|
}
|
|
else
|
|
{
|
|
return URLEncoder.encode(s);
|
|
}
|
|
}
|
|
catch (UnsupportedEncodingException err)
|
|
{
|
|
throw new RuntimeException(err);
|
|
}
|
|
}
|
|
|
|
public final static String decodeURL(String s)
|
|
{
|
|
return URLDecoder.decode(s);
|
|
}
|
|
|
|
/**
|
|
* Replace one string instance with another within the specified string
|
|
*
|
|
* @return Returns the replaced string
|
|
*/
|
|
public static String replace(String str, String repl, String with)
|
|
{
|
|
int lastindex = 0;
|
|
int pos = str.indexOf(repl);
|
|
|
|
// If no replacement needed, return the original string
|
|
// and save StringBuffer allocation/char copying
|
|
if (pos < 0)
|
|
{
|
|
return str;
|
|
}
|
|
|
|
int len = repl.length();
|
|
int lendiff = with.length() - repl.length();
|
|
StringBuilder out = new StringBuilder((lendiff <= 0) ? str.length() : (str.length() + (lendiff << 3)));
|
|
for (; pos >= 0; pos = str.indexOf(repl, lastindex = pos + len))
|
|
{
|
|
out.append(str.substring(lastindex, pos)).append(with);
|
|
}
|
|
|
|
return out.append(str.substring(lastindex, str.length())).toString();
|
|
}
|
|
|
|
/**
|
|
* Encodes the given string to valid HTML format
|
|
*
|
|
* @param string the String to convert
|
|
*/
|
|
public final static String encodeHTML(String string)
|
|
{
|
|
if (string == null)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
StringBuilder sb = null; //create on demand
|
|
String enc;
|
|
char c;
|
|
for (int i = 0; i < string.length(); i++)
|
|
{
|
|
enc = null;
|
|
c = string.charAt(i);
|
|
switch (c)
|
|
{
|
|
case '"': enc = """; break; //"
|
|
case '&': enc = "&"; break; //&
|
|
case '<': enc = "<"; break; //<
|
|
case '>': enc = ">"; break; //>
|
|
|
|
//misc
|
|
case '\u20AC': enc = "€"; break;
|
|
case '\u00AB': enc = "«"; break;
|
|
case '\u00BB': enc = "»"; break;
|
|
case '\u00A0': enc = " "; break;
|
|
|
|
default:
|
|
if (((int)c) >= 0x80)
|
|
{
|
|
//encode all non basic latin characters
|
|
enc = "&#" + ((int)c) + ";";
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (enc != null)
|
|
{
|
|
if (sb == null)
|
|
{
|
|
String soFar = string.substring(0, i);
|
|
sb = new StringBuilder(i + 8);
|
|
sb.append(soFar);
|
|
}
|
|
sb.append(enc);
|
|
}
|
|
else
|
|
{
|
|
if (sb != null)
|
|
{
|
|
sb.append(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sb == null)
|
|
{
|
|
return string;
|
|
}
|
|
else
|
|
{
|
|
return sb.toString();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ALF-5333: Microsoft clients use ISO-8859-1 to decode WebDAV responses
|
|
* so this method should only be used for Microsoft user agents.
|
|
*
|
|
* @param string
|
|
* @return The encoded string for Microsoft clients
|
|
* @throws UnsupportedEncodingException
|
|
*/
|
|
public final static String encodeUrlReservedSymbols(String string) throws UnsupportedEncodingException
|
|
{
|
|
if (string == null)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
StringBuilder sb = null; // create on demand
|
|
String enc;
|
|
char c;
|
|
for (int i = 0; i < string.length(); i++)
|
|
{
|
|
enc = null;
|
|
c = string.charAt(i);
|
|
switch (c)
|
|
{
|
|
// reserved
|
|
case ';': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '/': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '?': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case ':': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '@': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '&': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '=': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '+': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
|
|
// unsafe
|
|
case '\"': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '#': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '%': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '>': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
case '<': enc = URLEncoder.encode(String.valueOf(c)); break;
|
|
default: break;
|
|
}
|
|
|
|
if (enc != null)
|
|
{
|
|
if (sb == null)
|
|
{
|
|
String soFar = string.substring(0, i);
|
|
sb = new StringBuilder(i + 8);
|
|
sb.append(soFar);
|
|
}
|
|
sb.append(enc);
|
|
}
|
|
else
|
|
{
|
|
if (sb != null)
|
|
{
|
|
sb.append(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sb == null)
|
|
{
|
|
return string;
|
|
}
|
|
else
|
|
{
|
|
return sb.toString();
|
|
}
|
|
}
|
|
|
|
public String determineSiteId(WebDAVMethod method)
|
|
{
|
|
SiteService siteService = getServiceRegistry().getSiteService();
|
|
String siteId;
|
|
try
|
|
{
|
|
FileInfo fileInfo = getNodeForPath(method.getRootNodeRef(), method.getPath(), method.getServletPath());
|
|
SiteInfo siteInfo = siteService.getSite(fileInfo.getNodeRef());
|
|
if (siteInfo != null)
|
|
{
|
|
siteId = siteInfo.getShortName();
|
|
}
|
|
else
|
|
{
|
|
throw new RuntimeException("Node is not contained by a site: " + method.getPath());
|
|
}
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
siteId = EMPTY_SITE_ID;
|
|
}
|
|
return siteId;
|
|
}
|
|
|
|
public String determineTenantDomain(WebDAVMethod method)
|
|
{
|
|
TenantService tenantService = getTenantService();
|
|
String tenantDomain = tenantService.getCurrentUserDomain();
|
|
if (tenantDomain == null)
|
|
{
|
|
return TenantService.DEFAULT_DOMAIN;
|
|
}
|
|
return tenantDomain;
|
|
}
|
|
|
|
/**
|
|
* Extract the destination path for MOVE or COPY commands from the
|
|
* supplied destination URL header.
|
|
*
|
|
* @param servletPath Path prefix of the WebDAV servlet.
|
|
* @param destURL The Destination header.
|
|
* @return The path to move/copy the file to.
|
|
*/
|
|
public String getDestinationPath(String servletPath, String destURL)
|
|
{
|
|
if (destURL != null && destURL.length() > 0)
|
|
{
|
|
int offset = -1;
|
|
|
|
if (destURL.startsWith(HTTP_SCHEME))
|
|
{
|
|
// Set the offset to the start of the host name
|
|
offset = HTTP_SCHEME.length();
|
|
}
|
|
else if (destURL.startsWith(HTTPS_SCHEME))
|
|
{
|
|
// Set the offset to the start of the host name
|
|
offset = HTTPS_SCHEME.length();
|
|
}
|
|
|
|
// Strip the start of the path if not a relative path
|
|
|
|
if (offset != -1)
|
|
{
|
|
offset = destURL.indexOf(WebDAV.PathSeperator, offset);
|
|
if (offset != -1)
|
|
{
|
|
String strPath = destURL.substring(offset);
|
|
offset = strPath.indexOf(servletPath);
|
|
if (offset != -1)
|
|
strPath = strPath.substring(offset + servletPath.length());
|
|
|
|
return WebDAV.decodeURL(strPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unable to get the path.
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check that the destination path is on this server and is a valid WebDAV
|
|
* path for this server
|
|
*
|
|
* @param request The request made against the WebDAV server.
|
|
* @param urlStr String
|
|
* @exception WebDAVServerException
|
|
*/
|
|
public void checkDestinationURL(HttpServletRequest request, String urlStr) throws WebDAVServerException
|
|
{
|
|
try
|
|
{
|
|
// Parse the URL
|
|
|
|
URL url = new URL(urlStr);
|
|
|
|
// Check if the path is on this WebDAV server
|
|
|
|
boolean localPath = true;
|
|
|
|
if (url.getPort() != -1 && url.getPort() != request.getServerPort())
|
|
{
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Destination path, different server port");
|
|
|
|
localPath = false;
|
|
}
|
|
else if (url.getHost().equalsIgnoreCase(request.getServerName()) == false
|
|
&& url.getHost().equals(request.getLocalAddr()) == false)
|
|
{
|
|
// The target host may contain a domain or be specified as a numeric IP address
|
|
|
|
String targetHost = url.getHost();
|
|
|
|
if ( IPAddress.isNumericAddress( targetHost) == false)
|
|
{
|
|
String localHost = request.getServerName();
|
|
|
|
int pos = targetHost.indexOf( ".");
|
|
if ( pos != -1)
|
|
targetHost = targetHost.substring( 0, pos);
|
|
|
|
pos = localHost.indexOf( ".");
|
|
if ( pos != -1)
|
|
localHost = localHost.substring( 0, pos);
|
|
|
|
// compare the host names
|
|
|
|
if ( targetHost.equalsIgnoreCase( localHost) == false)
|
|
localPath = false;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// Check if the target IP address is a local address
|
|
|
|
InetAddress targetAddr = InetAddress.getByName( targetHost);
|
|
if ( NetworkInterface.getByInetAddress( targetAddr) == null)
|
|
localPath = false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// DEBUG
|
|
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("Failed to check target IP address, " + targetHost);
|
|
|
|
localPath = false;
|
|
}
|
|
}
|
|
|
|
// Debug
|
|
|
|
if (localPath == false && logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Destination path, different server name/address");
|
|
logger.debug(" URL host=" + url.getHost() + ", ServerName=" + request.getServerName() + ", localAddr=" + request.getLocalAddr());
|
|
}
|
|
}
|
|
else if (url.getPath().indexOf(request.getServletPath()) == -1)
|
|
{
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Destination path, different serlet path");
|
|
|
|
localPath = false;
|
|
}
|
|
|
|
// If the URL does not refer to this WebDAV server throw an
|
|
// exception
|
|
|
|
if (localPath != true)
|
|
throw new WebDAVServerException(HttpServletResponse.SC_BAD_GATEWAY);
|
|
}
|
|
catch (MalformedURLException ex)
|
|
{
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Bad destination path, " + urlStr);
|
|
|
|
throw new WebDAVServerException(HttpServletResponse.SC_BAD_GATEWAY);
|
|
}
|
|
}
|
|
}
|