WebdavUtils.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
org.apache.slide.webdav.util |
![]() |
![]() |
Jakarta Slide |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* $Header$
* $Revision: 208614 $
* $Date: 2005-05-27 13:20:19 -0400 (Fri, 27 May 2005) $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.slide.webdav.util;
import java.net.SocketException;
import java.security.Principal;
import java.util.Enumeration;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.common.Domain;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenImpl;
import org.apache.slide.content.Content;
import org.apache.slide.content.InsufficientStorageException;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.event.VetoException;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.macro.ConflictException;
import org.apache.slide.macro.ForbiddenException;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.security.UnauthenticatedException;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.method.MethodNotAllowedException;
/**
* A collection of various utility and convenience methods.
*
*
* @version $Revision: 208614 $
**/
public class WebdavUtils {
private static final String CREDENTIALS_ATTRIBUTE =
"org.apache.slide.webdav.method.credentials";
private static final String LOG_CHANNEL =
WebdavUtils.class.getName();
/**
* Constructs a new String based on bytes sequence contained
* in the
* Non-ASCII parts of the sequence will be decoded with UTF-8
* if possible, or with the specified encoding.
*
* @param string A "String" returned by tomcat getPathInfo()
* @param enc Encoding to use if non UTF-8
* @return A properly encoded String object
*/
public static String decodeString(String string, String enc)
throws UnsupportedEncodingException {
if(string == null)
return null;
StringBuffer sb = null;
int j = 0;
int sf = 0;
sb = new StringBuffer();
byte utf8buffer[] = new byte[5];
// Get bytes without any decoding
byte bytes[] = string.getBytes("ISO-8859-1");
for (int i = 0; i < bytes.length; i+=1) {
byte b = bytes[i];
int bb = (b >= 0) ? b : b+256;
utf8buffer[j++] = b;
boolean ok = false;
// First test if non-ascii
if (bb >= 128) {
// No ongoing UTF-8 decoding ?
if (sf==0) {
// Now test if this can be a UTF-8 first byte
if (bb >= 192 && i < 252) {
ok = true;
// Determine UTF-8 size
if (bb >= 224)
if (bb >= 240)
if (bb >= 248)
sf = 4;
else
sf = 3;
else
sf = 2;
else
sf = 1;
}
} else if (bb >= 128 && bb < 192) {
// This is a UTF-8 part
sf--;
if (sf == 0) {
sb.append(new String(utf8buffer,0,j,"UTF-8"));
j = 0;
}
ok = true;
}
}
// If there was an error during UTF-8 decoding, decode all remaining chars with default encoding
if (!ok) {
sb.append(new String(utf8buffer,0,j, enc));
j = 0;
sf = 0;
}
}
// Remaining chars
if (j > 0) {
sb.append(new String(utf8buffer,0,j, enc));
}
return sb.toString();
}
/**
* Return a context-relative path, beginning with a "/", that represents
* the canonical version of the specified path after ".." and "." elements
* are resolved out. If the specified path attempts to go outside the
* boundaries of the current context (i.e. too many ".." path elements
* are present), return <code>null</code> instead.
*
* @param path the path to be normalized
**/
public static String normalizeURL(String path) {
if (path == null)
return null;
String normalized = path;
if (normalized == null)
return (null);
// Normalize the slashes and add leading slash if necessary
if (normalized.indexOf('\\') >= 0)
normalized = normalized.replace('\\', '/');
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
return (null); // Trying to go outside our context
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
normalized = normalized.replace('?','_');
// Return the normalized path that we have completed
return (normalized);
}
/**
* URL rewriter.
*
* @param path the path to be rewritten
**/
public static String encodeURL(String path) {
return URLUtil.URLEncode(path, Configuration.realUrlEncoding());
}
/**
* URL rewriter.
*
* @param path the path to be rewritten
* @param enc the encoding
**/
public static String encodeURL(String path, String enc) {
return URLUtil.URLEncode(path, enc);
}
/**
* Maps the URI of a node in the Slide namespace to an external URI as seen
* by clients. This involves adding the context and servlet path to the
* URI.
*
* @param uri the node's URI
* @param config configuration of the WebdavServlet
*
* @return the node's URI as absolute path
**/
public static String getAbsolutePath
(String uri, HttpServletRequest req, WebdavServletConfig config)
{
return getAbsolutePath (uri, req.getContextPath(), req.getServletPath(), config);
}
/**
* Maps the URI of a node in the Slide namespace to an external URI as seen
* by clients. This involves adding the context and servlet path to the
* URI.
*
* @param uri the node's URI
* @param servletPath a String, the result of HttpRequest.getServletPath()
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param config configuration of the WebdavServlet
*
* @return a String
*
*/
public static String getAbsolutePath (String uri, String contextPath,
String servletPath,
WebdavServletConfig config)
{
String result = uri;
String scope = config.getScope();
int scopeLength = scope.length();
if (scopeLength > 0 && uri.startsWith(scope)) {
result = uri.substring(scopeLength);
}
if (!config.isDefaultServlet()) {
contextPath += servletPath;
}
result = contextPath + result;
return encodeURL(result);
}
public static String getAbsolutePath (String uri, String slideContextPath,
WebdavServletConfig config)
{
String result = uri;
String scope = config.getScope();
int scopeLength = scope.length();
if (scopeLength > 0 && uri.startsWith(scope)) {
result = uri.substring(scopeLength);
}
result = slideContextPath + result;
return encodeURL(result);
}
public static String getAbsolutePath (String uri, WebdavContext context)
{
String result = uri;
String scope = context.getServletConfig().getScope();
int scopeLength = scope.length();
if (scopeLength > 0 && uri.startsWith(scope)) {
result = uri.substring(scopeLength);
}
result = context.getContextPath() + result;
return encodeURL(result);
}
/**
* Maps the request URI of a HTTP request to a URI in the Slide namespace
* (this does not necessarily mean that a node exists at that URI).
*
* @param req the request object
* @param config configuration of the WebdavServlet
*
* @return the request URI mapped into the Slide namespace
**/
public static String getRelativePath
(HttpServletRequest req, WebdavServletConfig config) {
// get the requested path, depending on whether the servlet is mapped
// as default servlet.
String result = null;
String pathMapperClassName = config.getInitParameter("path-mapper-hook");
if (pathMapperClassName != null) {
try {
Class storeClass = Class.forName(pathMapperClassName);
PathMapper mapper = (PathMapper) storeClass.newInstance();
result = mapper.map(req, config);
} catch (Exception e) {
Domain.log(e, LOG_CHANNEL, Logger.WARNING);
}
}
if (result == null) {
PathMapper mapper = (PathMapper) config.getServletContext().getAttribute(
"org.apache.slide.webdav.util.PathMapper");
if (mapper != null) {
result = mapper.map(req, config);
}
}
if (result == null) {
if (config.isDefaultServlet()) {
result = req.getServletPath();
} else {
result = req.getRequestURI();
result = result.substring(req.getContextPath().length()+ req.getServletPath().length());
}
}
// default to the namespace root if no path-info is specified
if ((result == null) || (result.length() == 0)) {
result = "/";
}
// prefix the URI with the configured scope
result = config.getScope() + result;
result = normalizeURL(fixTomcatURL(result)); // the request URL is utf-8 encoded
return result;
}
/**
* Returns an URL based on input. The input URL is encoded with "fromEncoding".
* The resulting URL is encoded as specified in Configuration.urlEncoding()
*
* @param input the input URL
*
* @return a new URL encoded in Configuration.urlEncoding()
**/
public static String fixTomcatURL(String input) {
return fixTomcatHeader(input, "UTF-8");
}
/**
* Returns an decoded header value. The input header is encoded with "ISO-8859-1".
* The resulting header is encoded as specified in toEncoding
*
* @param header the input header
* @param toEncoding the target encoding of the header
*
* @return a new header value encoded in toEncoding
**/
public static String fixTomcatHeader(String header, String toEncoding) {
// todo: toEncoding parameter not used anymore
if (header == null) return null;
String result = null;
try {
result = URLUtil.URLDecode(header.getBytes("ISO-8859-1"),"ISO-8859-1");
result = decodeString(result,Configuration.urlEncoding());
if (!Configuration.useUTF8()) {
// Remove unsupported characters
result = new String(result.getBytes(Configuration.urlEncoding()),Configuration.urlEncoding());
}
} catch (Exception e) { e.printStackTrace(); }
return result;
}
/**
* Returns a SlideToken using the authentication information of an HTTP
* request.
*
* @param req the HTTP request
*
* @return a new SlideToken instance
**/
public static SlideToken getSlideToken(HttpServletRequest req) {
CredentialsToken credentialsToken;
Principal principal = req.getUserPrincipal();
HttpSession session = req.getSession();
// store the current principal in the session, to get around a bug in
// IE 5 where the authentication info is not submitted by IE when
// doing a HEAD request.
if (principal == null) {
final String credentials = (String) session.getAttribute(CREDENTIALS_ATTRIBUTE);
credentialsToken = new CredentialsToken(credentials == null ? "" : credentials);
} else {
// because the principal is not guaranteed to be serializable
// and could thus create problems in a distributed deployment
// we store the principal name instead of the principal itself
session.setAttribute(CREDENTIALS_ATTRIBUTE, principal.getName());
credentialsToken = new CredentialsToken(principal);
}
SlideToken token = new SlideTokenImpl(credentialsToken);
token.setEnforceLockTokens(true);
// store session attributes in token parameters to pass them through
// to the stores
for(Enumeration e = session.getAttributeNames(); e.hasMoreElements();) {
String name = (String)e.nextElement();
token.addParameter(name, session.getAttribute(name));
}
return token;
}
/**
* Tests whether a given path maps to a URI in the Slide namespace that
* identifies a collection resource.
*
* @param token the namespace access token
* @param slideToken the slide token
* @param path relative path of the resource
*
* @return true if the requested resource is a collection, false otherwise
**/
public static boolean isCollection
(NamespaceAccessToken token, SlideToken slideToken,
String path) {
// Added for DeltaV --start--
if( Configuration.useVersionControl() ) {
UriHandler uh = UriHandler.getUriHandler( path );
if( uh.isWorkspaceUri() )
return true;
if( uh.isHistoryUri() )
return true;
if( uh.isVersionUri() )
return false;
}
// Added for DeltaV --end--
try {
Content content = token.getContentHelper();
NodeRevisionDescriptors revisionDescriptors =
content.retrieve(slideToken, path);
if (revisionDescriptors.hasRevisions()) {
NodeRevisionDescriptor revisionDescriptor =
content.retrieve(slideToken, revisionDescriptors);
return isCollection(revisionDescriptor);
} else {
return true;
}
} catch(ObjectNotFoundException e) {
// if the Object is not found return false for no 207 is generated
return false;
} catch(SlideException e) {
// this is the default
return true;
}
}
/**
* Tests whether a resource is a collection resource.
*
* @param revisionDescriptor revision descriptor of the resource
*
* @return true if the descriptor represents a collection, false otherwise
**/
public static boolean isCollection
(NodeRevisionDescriptor revisionDescriptor) {
boolean result = false;
if (revisionDescriptor == null)
return true;
if (revisionDescriptor.propertyValueContains(
NodeRevisionDescriptor.RESOURCE_TYPE ,"collection")) {
result = true;
}
return result;
}
/**
* Tests whether a resource is a redirect reference.
*
* @param revisionDescriptor revision descriptor of the resource
*
* @return <code>true</code> if the descriptor represents a redirect
* reference, <code>false</code> otherwise.
*/
public static boolean isRedirectref
(NodeRevisionDescriptor revisionDescriptor) {
if (revisionDescriptor == null)
return false;
return revisionDescriptor.propertyValueContains(
NodeRevisionDescriptor.RESOURCE_TYPE, "redirectref");
}
public static String getSlidePath(String fullpath, String slideContextPath) {
// strip off the protocol://host:port part
if (fullpath.indexOf("://") >= 0) {
fullpath=fullpath.substring(fullpath.indexOf("://")+3);
fullpath=fullpath.substring(fullpath.indexOf("/"));
}
// strip off the servlet context path
if (fullpath.startsWith(slideContextPath)) {
fullpath=fullpath.substring(slideContextPath.length());
}
return fullpath;
}
/**
* Get return status based on exception type.
*/
public static int getErrorCode(Throwable ex) {
if ( !(ex instanceof SlideException) ) {
// if( ex != null ) ex.printStackTrace();
return WebdavStatus.SC_INTERNAL_SERVER_ERROR;
} else {
return getErrorCode((SlideException)ex);
}
}
/**
* Get return status based on exception type.
*/
public static int getErrorCode(SlideException ex) {
try {
throw ex;
} catch(ObjectNotFoundException e) {
return WebdavStatus.SC_NOT_FOUND;
} catch(ConflictException e) {
return WebdavStatus.SC_CONFLICT;
} catch(ForbiddenException e) {
return WebdavStatus.SC_FORBIDDEN;
} catch(AccessDeniedException e) {
return WebdavStatus.SC_FORBIDDEN;
} catch(UnauthenticatedException e) {
return WebdavStatus.SC_UNAUTHORIZED;
} catch(ObjectAlreadyExistsException e) {
return WebdavStatus.SC_PRECONDITION_FAILED;
} catch(ServiceAccessException e) {
return getErrorCode((ServiceAccessException)ex);
} catch(ObjectLockedException e) {
return WebdavStatus.SC_LOCKED;
} catch(WebdavException e) {
return e.getStatusCode();
} catch(MethodNotAllowedException e) {
return WebdavStatus.SC_METHOD_NOT_ALLOWED;
} catch(InsufficientStorageException e) {
return WebdavStatus.SC_INSUFFICIENT_STORAGE;
} catch(VetoException e) {
if (e != e.getCause()) {
return getErrorCode(e.getCause());
}
return WebdavStatus.SC_NOT_ACCEPTABLE;
} catch(SlideException e) {
return WebdavStatus.SC_INTERNAL_SERVER_ERROR;
}
}
/**
* Get return status based on exception type.
*/
public static int getErrorCode(ServiceAccessException ex) {
Throwable cause = ex.getCauseException();
// XXX SocketException pops up when the client closes the connection in the middle of transferring
// the HTTP body, so this is no internal error, really!
if (cause != null && cause instanceof SocketException) {
// XXX is this a reasonable code?
return WebdavStatus.SC_PRECONDITION_FAILED;
} else if (cause == null || !(cause instanceof SlideException)) {
// ex.printStackTrace();
if( cause != null ) cause.printStackTrace();
return WebdavStatus.SC_INTERNAL_SERVER_ERROR; // this is the default}
} else {
return getErrorCode((SlideException)cause);
}
}
}
The table below shows all metrics for WebdavUtils.java.




