Fixed AR-1321: Allow '&' in filename

The following filename is valid now: "x ¬ £ % & + ; x.txt"
This was a restriction imposed by WebDAV, but the encoding of the repsonses is working well and these restrictions be removed as a result.

Fixed AR-1281: WebDAV upload was assigning incorrect encoding

I added a bean 'charset.finder', which can be fetched from the MimetypeService.
Various pluggins now exist to decode a stream and figure out what the encoding is.
WebDAV and CIFS/FTP are now hooked into this so that they guess a little better.

Fixed others:
Added retrying transactions to WebDAV.
Read/write transactions for WebDAV.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6073 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-06-22 21:27:17 +00:00
parent 559d92956c
commit 079ee79f52
6 changed files with 75 additions and 83 deletions

View File

@@ -141,6 +141,15 @@ public class GetMethod extends WebDAVMethod
// Nothing to do in this method // Nothing to do in this method
} }
/**
* @return Returns <tt>true</tt> always
*/
@Override
protected boolean isReadOnly()
{
return true;
}
/** /**
* Exceute the WebDAV request * Exceute the WebDAV request
* *

View File

@@ -69,6 +69,15 @@ public class OptionsMethod extends WebDAVMethod
// Nothing to do in this method // Nothing to do in this method
} }
/**
* @return Returns <tt>true</tt> always
*/
@Override
protected boolean isReadOnly()
{
return true;
}
/** /**
* Perform the main request processing * Perform the main request processing
* *

View File

@@ -24,14 +24,17 @@
*/ */
package org.alfresco.repo.webdav; package org.alfresco.repo.webdav;
import java.io.BufferedInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
@@ -142,23 +145,28 @@ public class PutMethod extends WebDAVMethod
// Access the content // Access the content
ContentWriter writer = fileFolderService.getWriter(contentNodeInfo.getNodeRef()); ContentWriter writer = fileFolderService.getWriter(contentNodeInfo.getNodeRef());
// set content properties // set content properties
String mimetype = null;
if (m_strContentType != null) if (m_strContentType != null)
{ {
writer.setMimetype(m_strContentType); mimetype = m_strContentType;
} }
else else
{ {
String guessedMimetype = getServiceRegistry().getMimetypeService().guessMimetype(contentNodeInfo.getName()); String guessedMimetype = getMimetypeService().guessMimetype(contentNodeInfo.getName());
writer.setMimetype(guessedMimetype); mimetype = guessedMimetype;
} }
// use default encoding writer.setMimetype(mimetype);
writer.setEncoding("UTF-8");
// Get the input stream from the request data // Get the input stream from the request data
InputStream input = m_request.getInputStream(); InputStream is = m_request.getInputStream();
is = is.markSupported() ? is : new BufferedInputStream(is);
ContentCharsetFinder charsetFinder = getMimetypeService().getContentCharsetFinder();
Charset encoding = charsetFinder.getCharset(is, mimetype);
writer.setEncoding(encoding.name());
// Write the new data to the content node // Write the new data to the content node
writer.putContent(input); writer.putContent(is);
// Set the response status, depending if the node existed or not // Set the response status, depending if the node existed or not
m_response.setStatus(created ? HttpServletResponse.SC_CREATED : HttpServletResponse.SC_NO_CONTENT); m_response.setStatus(created ? HttpServletResponse.SC_CREATED : HttpServletResponse.SC_NO_CONTENT);

View File

@@ -88,9 +88,6 @@ public class WebDAVHelper
/** /**
* Class constructor * Class constructor
*
* @param serviceRegistry ServiceRegistry
* @param authService AuthenticationService
*/ */
protected WebDAVHelper(ServiceRegistry serviceRegistry, AuthenticationService authService) protected WebDAVHelper(ServiceRegistry serviceRegistry, AuthenticationService authService)
{ {
@@ -108,9 +105,7 @@ public class WebDAVHelper
} }
/** /**
* Return the authentication service * @return Return the authentication service
*
* @return AuthenticationService
*/ */
public final AuthenticationService getAuthenticationService() public final AuthenticationService getAuthenticationService()
{ {
@@ -118,9 +113,7 @@ public class WebDAVHelper
} }
/** /**
* Return the service registry * @return Return the service registry
*
* @return ServiceRegistry
*/ */
public final ServiceRegistry getServiceRegistry() public final ServiceRegistry getServiceRegistry()
{ {
@@ -128,9 +121,7 @@ public class WebDAVHelper
} }
/** /**
* Return the node service * @return Return the node service
*
* @return NodeService
*/ */
public final NodeService getNodeService() public final NodeService getNodeService()
{ {
@@ -143,9 +134,7 @@ public class WebDAVHelper
} }
/** /**
* Return the search service * @return Return the search service
*
* @return SearchService
*/ */
public final SearchService getSearchService() public final SearchService getSearchService()
{ {
@@ -153,9 +142,7 @@ public class WebDAVHelper
} }
/** /**
* Return the namespace service * @return Return the namespace service
*
* @return NamespaceService
*/ */
public final NamespaceService getNamespaceService() public final NamespaceService getNamespaceService()
{ {
@@ -163,9 +150,7 @@ public class WebDAVHelper
} }
/** /**
* Return the dictionary service * @return Return the dictionary service
*
* @return DictionaryService
*/ */
public final DictionaryService getDictionaryService() public final DictionaryService getDictionaryService()
{ {
@@ -173,9 +158,7 @@ public class WebDAVHelper
} }
/** /**
* Return the mimetype service * @return Return the mimetype service
*
* @return MimetypeService
*/ */
public final MimetypeService getMimetypeService() public final MimetypeService getMimetypeService()
{ {
@@ -183,9 +166,7 @@ public class WebDAVHelper
} }
/** /**
* Return the lock service * @return Return the lock service
*
* @return LockService
*/ */
public final LockService getLockService() public final LockService getLockService()
{ {
@@ -193,9 +174,7 @@ public class WebDAVHelper
} }
/** /**
* Return the copy service * @return Return the copy service
*
* @return CopyService
*/ */
public final CopyService getCopyService() public final CopyService getCopyService()
{ {
@@ -237,8 +216,8 @@ public class WebDAVHelper
/** /**
* Split the path into all the component directories and filename * Split the path into all the component directories and filename
* *
* @param path String * @param path the string to split
* @return String[] * @return an array of all the path components
*/ */
public final List<String> splitAllPaths(String path) public final List<String> splitAllPaths(String path)
{ {
@@ -260,11 +239,12 @@ public class WebDAVHelper
/** /**
* Get the file info for the given paths * Get the file info for the given paths
* *
* @param rootNodeRef the acting webdav root * @param rootNodeRef the acting webdav root
* @param path the path to search for * @param path the path to search for
* @param servletPath the base servlet path, which may be null or empty * @param servletPath the base servlet path, which may be null or empty
* @return Return the file info for the path * @return Return the file info for the path
* @throws FileNotFoundException if the path doesn't refer to a valid node * @throws FileNotFoundException
* if the path doesn't refer to a valid node
*/ */
public final FileInfo getNodeForPath(NodeRef rootNodeRef, String path, String servletPath) throws FileNotFoundException public final FileInfo getNodeForPath(NodeRef rootNodeRef, String path, String servletPath) throws FileNotFoundException
{ {
@@ -366,9 +346,6 @@ public class WebDAVHelper
/** /**
* Make an ETag value for a node using the GUID and modify date/time * Make an ETag value for a node using the GUID and modify date/time
*
* @param node NodeRef
* @return String
*/ */
public final String makeETag(NodeRef node) public final String makeETag(NodeRef node)
{ {
@@ -381,9 +358,6 @@ public class WebDAVHelper
/** /**
* Make an ETag value for a node using the GUID and modify date/time * Make an ETag value for a node using the GUID and modify date/time
*
* @param node NodeRef
* @return String
*/ */
public final String makeQuotedETag(NodeRef node) public final String makeQuotedETag(NodeRef node)
{ {
@@ -397,9 +371,6 @@ public class WebDAVHelper
/** /**
* Make an ETag value for a node using the GUID and modify date/time * Make an ETag value for a node using the GUID and modify date/time
*
* @param node NodeRef
* @param str StringBuilder
*/ */
protected final void makeETagString(NodeRef node, StringBuilder etag) protected final void makeETagString(NodeRef node, StringBuilder etag)
{ {
@@ -417,9 +388,7 @@ public class WebDAVHelper
} }
/** /**
* Return the null XML attribute list * @return Return the null XML attribute list
*
* @return AttributesImpl
*/ */
public final AttributesImpl getNullAttributes() public final AttributesImpl getNullAttributes()
{ {
@@ -429,7 +398,7 @@ public class WebDAVHelper
/** /**
* Encodes the given string to valid URL format * Encodes the given string to valid URL format
* *
* @param s the String to convert * @param s the String to convert
*/ */
public final static String encodeURL(String s) public final static String encodeURL(String s)
{ {
@@ -446,11 +415,7 @@ public class WebDAVHelper
/** /**
* Replace one string instance with another within the specified string * Replace one string instance with another within the specified string
* *
* @param str * @return Returns the replaced string
* @param repl
* @param with
*
* @return replaced string
*/ */
public static String replace(String str, String repl, String with) public static String replace(String str, String repl, String with)
{ {
@@ -478,7 +443,7 @@ public class WebDAVHelper
/** /**
* Encodes the given string to valid HTML format * Encodes the given string to valid HTML format
* *
* @param string the String to convert * @param string the String to convert
*/ */
public final static String encodeHTML(String string) public final static String encodeHTML(String string)
{ {

View File

@@ -37,8 +37,7 @@ import javax.xml.parsers.ParserConfigurationException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.transaction.TransactionUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
@@ -114,11 +113,23 @@ public abstract class WebDAVMethod
m_strPath = WebDAV.getRepositoryPath(req); m_strPath = WebDAV.getRepositoryPath(req);
} }
/**
* Override and return <tt>true</tt> if the method is a query method only. The default implementation
* returns <tt>false</tt>.
*
* @return Returns <tt>true</tt> if the method transaction may be read-only
*/
protected boolean isReadOnly()
{
return false;
}
/** /**
* Executes the method * Executes the method, wrapping the call to {@link #executeImpl()} in an appropriate transaction
* and handling the error conditions.
*/ */
public void execute() throws WebDAVServerException public final void execute() throws WebDAVServerException
{ {
// Parse the HTTP headers // Parse the HTTP headers
parseRequestHeaders(); parseRequestHeaders();
@@ -126,9 +137,9 @@ public abstract class WebDAVMethod
// Parse the HTTP body // Parse the HTTP body
parseRequestBody(); parseRequestBody();
TransactionWork<WebDAVServerException> executeWork = new TransactionWork<WebDAVServerException>() RetryingTransactionCallback<Object> executeImplCallback = new RetryingTransactionCallback<Object>()
{ {
public WebDAVServerException doWork() throws Exception public Object execute() throws Exception
{ {
executeImpl(); executeImpl();
return null; return null;
@@ -136,9 +147,9 @@ public abstract class WebDAVMethod
}; };
try try
{ {
boolean isReadOnly = isReadOnly();
// Execute the method // Execute the method
TransactionService transactionService = getTransactionService(); getTransactionService().getRetryingTransactionHelper().doInTransaction(executeImplCallback, isReadOnly);
TransactionUtil.executeInUserTransaction(transactionService, executeWork);
} }
catch (AccessDeniedException e) catch (AccessDeniedException e)
{ {

View File

@@ -37,8 +37,6 @@ import javax.transaction.UserTransaction;
import org.alfresco.filesys.server.config.ServerConfiguration; import org.alfresco.filesys.server.config.ServerConfiguration;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -127,16 +125,8 @@ public class WebDAVServlet extends HttpServlet
return; return;
} }
// Execute the WebDAV request, wrapped in a transaction // Execute the WebDAV request, which must take care of its own transaction
TransactionWork<Object> methodWork = new TransactionWork<Object>() method.execute();
{
public Object doWork() throws Exception
{
method.execute();
return null;
}
};
TransactionUtil.executeInUserTransaction(m_transactionService, methodWork);
} }
catch (Throwable e) catch (Throwable e)
{ {