/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AbstractWebdavMethod.java,v 1.20.2.3 2004/04/01 13:46:39 ozeigermann Exp $
* $Revision: 1.20.2.3 $
* $Date: 2004/04/01 13:46:39 $
*
* ====================================================================
*
* 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.method;
import java.io.IOException;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.slide.common.Domain;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NestedSlideException;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenWrapper;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.lock.Lock;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.lock.UnlockListener;
import org.apache.slide.macro.Macro;
import org.apache.slide.search.Search;
import org.apache.slide.security.Security;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.Structure;
import org.apache.slide.util.Messages;
import org.apache.slide.util.XMLValue;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavMethod;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.util.BindConstants;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.PreconditionViolationException;
import org.apache.slide.webdav.util.UnlockListenerImpl;
import org.apache.slide.webdav.util.ViolatedPrecondition;
import org.apache.slide.webdav.util.WebdavConstants;
import org.apache.slide.webdav.util.WebdavUtils;
import org.apache.util.MD5Encoder;
import org.apache.util.WebdavStatus;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
/**
* WebDAV method.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @author Christopher Lenz
*/
public abstract class AbstractWebdavMethod
implements WebdavMethod, WebdavConstants, DeltavConstants, BindConstants {
// -------------------------------------------------------------- Constants
/**
* String constant for <code>no-cache</code>.
*/
protected static final String NO_CACHE = "no-cache";
/**
* String constant for <code>http://</code>.
*/
public static final String HTTP_PROTOCOL = "http://";
/**
* String constant for <code>HTTP/1.1</code>.
*/
public static final String HTTP_VERSION = "HTTP/1.1";
/**
* String constant for <code>text/xml</code>.
*/
public static final String TEXT_XML = "text/xml";
/**
* String constant for <code>text/xml; charset="UTF-8"</code>.
*/
public static final String TEXT_XML_UTF_8 = "text/xml; charset=\"UTF-8\"";
/**
* The indent to use in the XML response.
*/
public static final String XML_REPONSE_INDENT = " ";
private static final String LOG_CHANNEL =
AbstractWebdavMethod.class.getName();
// public static final String PRINCIPAL =
// "org.apache.slide.webdav.method.principal";
protected static final int INFINITY = Integer.MAX_VALUE;
protected static final Namespace DNSP = NamespaceCache.DEFAULT_NAMESPACE;
// ----------------------------------------------------- Instance Variables
/**
* Requested Uri.
*/
protected String requestUri;
/**
* Servlet request.
*/
protected HttpServletRequest req;
/**
* Servlet response.
*/
protected HttpServletResponse resp;
/**
* Configuration.
*/
protected WebdavServletConfig config;
/**
* Request body.
*/
protected String requestBody;
/**
* Namespace access token.
*/
protected NamespaceAccessToken token;
/**
* Structure helper.
*/
protected Structure structure;
/**
* Content helper.
*/
protected Content content;
/**
* Security helper.
*/
protected Security security;
/**
* Lock helper.
*/
protected Lock lock;
/** wam
* Search helper.
*/
protected Search search;
/**
* Macro helper.
*/
protected Macro macro;
/**
* Slide token.
*/
protected SlideToken slideToken;
/**
* MD5 message digest provider.
*/
protected static MessageDigest md5Helper;
/**
* The MD5 helper object for this class.
*/
protected static final MD5Encoder md5Encoder = new MD5Encoder();
/**
* The request content (XML) Document.
*/
private Document requestContentDocument = null;
/**
* Indicates if the request content has already been parsed.
*/
private boolean isRequestContentParsed = false;
/**
* Request headers
*/
protected RequestHeaders requestHeaders = new RequestHeaders();
// -------------------------------------------------- Static Initialization
static {
// Load the MD5 helper used to calculate signatures.
try {
md5Helper = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
System.out.println(e.toString());
throw new IllegalStateException();
}
}
// ----------------------------------------------------------- Constructors
/**
* Constructor.
*
* @param token the token for accessing the namespace
* @param config configuration of the WebDAV servlet
*/
public AbstractWebdavMethod(NamespaceAccessToken token,
WebdavServletConfig config) {
this.config = config;
this.token = token;
// initialize helpers
structure = token.getStructureHelper();
content = token.getContentHelper();
security = token.getSecurityHelper();
lock = token.getLockHelper();
macro = token.getMacroHelper();
}
// -------------------------------------------- WebdavMethod Implementation
/**
* Exceute method.
*
* @exception WebdavException
*/
public void run(HttpServletRequest req, HttpServletResponse resp)
throws WebdavException {
this.req = req;
this.resp = resp;
this.slideToken = WebdavUtils.getSlideToken(req);
this.requestUri = WebdavUtils.getRelativePath(req, config);
parseRequestHeaders();
boolean transactionIsStarted = false;
try {
parseRequest();
if (methodNeedsTransactionSupport()) {
token.begin();
transactionIsStarted = true;
}
// clear expired lock-tokens
try {
UnlockListener listener =
new UnlockListenerImpl( slideToken, token, config, req, resp );
lock.clearExpiredLocks( slideToken, requestUri, listener );
// if the URI has no more locks associated to it and is
// a lock-null resource, we must attempt to delete it
Enumeration locks = lock.enumerateLocks(slideToken, requestUri);
if (!locks.hasMoreElements()) {
NodeRevisionDescriptors revisionDescriptors = content.retrieve(slideToken, requestUri);
NodeRevisionDescriptor revisionDescriptor = content.retrieve(slideToken, revisionDescriptors);
if (isLockNull(revisionDescriptor)) {
content.remove(slideToken, requestUri, revisionDescriptor);
content.remove(slideToken, revisionDescriptors);
ObjectNode node = structure.retrieve(slideToken, requestUri);
structure.remove(slideToken, node);
}
}
}
catch (SlideException e) {}
executeRequest();
if (methodNeedsTransactionSupport()) {
token.commit();
transactionIsStarted = false;
}
} catch (WebdavException ex) {
// Ignore the WebDav Exception and assume that the response code
// is already set.
} catch (Exception ex) {
token.getLogger().log(ex,LOG_CHANNEL,Logger.ERROR);
int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
sendError( statusCode, ex );
throw new WebdavException( statusCode );
} finally {
if (transactionIsStarted && methodNeedsTransactionSupport()) {
// Something went wrong, we are here and the TA is still open
try {
token.rollback();
} catch (Exception e) {
}
}
}
}
// --------------------------------------------------------- Public Methods
/**
* Returns the configuration of the WebdavServlet.
*
* @return WebdavServletConfig
*/
public WebdavServletConfig getConfig() {
return config;
}
/**
* Return an absolute path (absolute in the HTTP sense) based on a Slide
* path.
*/
public String getFullPath(String slidePath) {
return WebdavUtils.getAbsolutePath(slidePath, req, getConfig());
}
/**
* Returns a Slide path based on an absolute URL
* (absolute in the HTTP sense)
*/
public String getSlidePath(String fullpath) {
return WebdavUtils.getSlidePath(fullpath, req.getContextPath());
}
// ------------------------------------------------------ Protected Methods
/**
* Return true if the method needs transaction support.
* Return true if the method needs transaction support, e.g.
* the methods put, proppatch would need TA support. The
* methods get, propfind would not need transaction support.
*/
protected boolean methodNeedsTransactionSupport() {
return true;
// this method should return false and e.g. PutMethod should
// overwrite it to true, but PropFind creates a RevisionDescriptors
// on the fly
}
/**
* Read request contents.
*
* @param req Request object handed out by the servlet container
* @return char[] Array of char which contains the body of the request
*/
protected void readRequestContent() {
if (req.getContentLength() == 0)
return;
// TODO : Modify this and make it chunking aware
try {
requestBody = new String(NodeRevisionContent.read(req.getInputStream()),
getEncodingString(req.getCharacterEncoding()));
}
catch (Exception e) {
token.getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
}
}
/**
* Translate the encoding string into a proper Java encoding String.
*/
public static String getEncodingString(String httpEncoding) {
String result = httpEncoding;
if (result == null) result = System.getProperty("file.encoding");
if (result.startsWith("\"")) result = result.substring(1, result.length());
if (result.endsWith("\"")) result = result.substring(0, result.length()-1);
return result;
}
/**
* Method parseHeaders
*
*/
private void parseRequestHeaders() throws WebdavException {
requestHeaders.parse();
}
/**
* Test if a resource given by a path is a collection
*/
protected boolean isCollection(String path) {
return WebdavUtils.isCollection(token, slideToken, path);
}
/**
* Test whether the resource given by lowerNode is a descendant of the
* resource given by upperNode
*
* @param lowerNode an ObjectNode
* @param upperNode an ObjectNode
*
* @return true, if lowerNode is below upperNode in the namespace
* @throws ServiceAccessException
*
*/
protected boolean isDescendant( ObjectNode lowerNode, ObjectNode upperNode ) throws ServiceAccessException {
if (lowerNode.getUuri().equals(upperNode.getUuri())) {
return true;
}
if (upperNode.hasBinding(lowerNode)) {
return true;
}
// use a non-blocking slide token.
SlideToken stoken = readonlySlideToken();
NodeRevisionDescriptors lowerNrds = null;
NodeRevisionDescriptor lowerNrd = null;
try {
lowerNrds = content.retrieve(stoken, lowerNode.getUri());
lowerNrd = content.retrieve(stoken, lowerNrds);
NodeProperty psProp = lowerNrd.getProperty(P_PARENT_SET);
XMLValue xv = new XMLValue( String.valueOf(psProp.getValue()) );
Iterator i = xv.getList().iterator();
while (i.hasNext()) {
// iterate over parent elements
Element pElm = (Element)i.next();
String hrPath = pElm.getChild( E_HREF, DNSP ).getText();
ObjectNode hrNode = structure.retrieve( stoken, hrPath );
return isDescendant( hrNode, upperNode );
}
} catch (ServiceAccessException e) {
throw e;
} catch (Exception e) {}
return false;
}
/**
* Parse WebDAV XML query.
*
* @exception WebdavException
*/
protected abstract void parseRequest()
throws WebdavException;
/**
* Returns the request content (XML) Document.
*
* @return the request content (XML) Document.
*/
protected Document getRequestContent() {
return requestContentDocument;
}
//--
/**
* precondition: sourceUri != null
*/
protected String parseUri(String uri) throws WebdavException { // TODO: better name
int protocolIndex = uri.indexOf("://");
if (protocolIndex >= 0) {
// if the Destination URL contains the protocol, we can safely
// trim everything upto the first "/" character after "://"
int firstSeparator =
uri.indexOf("/", protocolIndex + 4);
if (firstSeparator < 0) {
uri = "/";
} else {
uri = uri.substring(firstSeparator);
}
} else {
String hostName = req.getServerName();
if ((hostName != null) && (uri.startsWith(hostName))) {
uri = uri.substring(hostName.length());
}
int portIndex = uri.indexOf(":");
if (portIndex >= 0) {
uri = uri.substring(portIndex);
}
if (uri.startsWith(":")) {
int firstSeparator = uri.indexOf("/");
if (firstSeparator < 0) {
uri = "/";
} else {
uri = uri.substring(firstSeparator);
}
}
}
// headers are "ISO-8859-1" encoded [not any more with TC 4.1.18
// destinationUri = WebdavUtils.decodeURL(WebdavUtils.fixTomcatURL(destinationUri, "ISO-8859-1"));
uri = WebdavUtils.decodeURL(uri);
String contextPath = req.getContextPath();
if ((contextPath != null) && (uri.startsWith(contextPath))) {
uri = uri.substring(contextPath.length());
}
String pathInfo = req.getPathInfo();
if (pathInfo != null) {
String servletPath = req.getServletPath();
if ((servletPath != null) && (uri.startsWith(servletPath))) {
uri = uri.substring(servletPath.length());
}
}
uri = getConfig().getScope() + uri;
return uri;
}
protected Element parseRequestContent(String rootName) throws JDOMException, IOException {
Document document;
Element root;
document = parseRequestContent();
if (document == null) {
throw new JDOMException("Request content missing");
}
root = document.getRootElement();
if( root == null || !root.getName().equals(rootName) ) {
Domain.warn( "Root element must be "+rootName );
throw new JDOMException("Root element must be <"+rootName+">");
}
return root;
}
/**
* Parses the request content (XML) Document.
*
* @return the request content (XML) Document.
*
* @throws IOException if an I/O error occurred.
* @throws JDOMException if parsing the document failed.
*/
protected Document parseRequestContent() throws JDOMException, IOException {
if (isRequestContentParsed) {
return requestContentDocument;
}
if (req.getContentLength() == 0) {
return requestContentDocument;
}
try {
requestContentDocument = new SAXBuilder().build(req.getInputStream());
isRequestContentParsed = true;
}
catch (JDOMException e) {
if (e.getCause() instanceof IOException) {
throw (IOException)e.getCause();
}
else {
throw e;
}
}
return requestContentDocument;
}
/**
* Generate XML response.
*
* @exception WebdavException
*/
protected abstract void executeRequest()
throws WebdavException, IOException;
/**
* Simulate MS IIS5 ?
*
* @return boolean
*/
protected boolean isMsProprietarySupport() {
return (token.getNamespaceConfig().getParameter("ms") != null);
}
/**
* Sends a precondition vilolation response.
*
* @param pve the ProconditionViolationException that describes the violated
* precondition.
*/
protected void sendPreconditionViolation(PreconditionViolationException pve) throws IOException {
if (pve != null) {
ViolatedPrecondition violatedPrecondition = pve.getViolatedPrecondition();
int statusCode = violatedPrecondition.getStatusCode();
printStackTrace( pve, statusCode );
String statusText = WebdavStatus.getStatusText(statusCode);
if (violatedPrecondition.getExplanation() != null) {
statusText = statusText+": "+violatedPrecondition.getExplanation();
}
resp.setStatus(statusCode, statusText);
resp.setContentType(TEXT_XML_UTF_8);
new XMLOutputter(XML_REPONSE_INDENT, true).
output(new Document(MethodUtil.getPreconditionViolationError(pve.getViolatedPrecondition())), resp.getWriter());
}
}
/**
* Returns the absolute URL of the given <code>uri</code>, e.g.
* if the server is <code>aloha.com:80</code>, context path is
* <code>have</code> and the URI is <code>much/fun</code> the string
* <code>http://aloha:80/have/much/fun</code>.
*
* @param uri the URI for which to return the URL (may be <code>null</code>).
*
* @return the absolute URL.
*/
protected String getAbsoluteURL(String uri) {
StringBuffer buffer = new StringBuffer();
buffer.append(HTTP_PROTOCOL);
buffer.append(req.getServerName());
buffer.append(":");
buffer.append(req.getServerPort());
if ( ! req.getContextPath().startsWith("/") ) {
buffer.append("/");
}
buffer.append(req.getContextPath());
if (uri != null) {
if ( !req.getContextPath().endsWith("/") && !uri.startsWith("/") ) {
buffer.append("/");
}
buffer.append(uri);
}
return buffer.toString();
}
// -------------------------------------------------------- Private Methods
/**
* Get return status based on exception type.
*/
protected int getErrorCode(Throwable ex) {
return WebdavUtils.getErrorCode(ex);
}
/**
* Get return status based on exception type.
*/
protected int getErrorCode(SlideException ex) {
return WebdavUtils.getErrorCode(ex);
}
/**
* Get return status based on exception type.
*/
protected int getErrorCode(ServiceAccessException ex) {
return WebdavUtils.getErrorCode(ex);
}
/**
* Returns the value of a boolean init parameter of the servlet.
* Default value: false.
*/
protected boolean getBooleanInitParameter( String name ) {
return "true".equalsIgnoreCase( getConfig().getInitParameter(name) );
}
/**
* Returns the value of an integer init parameter of the servlet.
* Default value: -1.
*/
protected int getIntInitParameter( String name ) {
int result = -1;
try {
result = Integer.parseInt( getConfig().getInitParameter(name) );
}
catch( NumberFormatException x ) {};
return result;
}
/**
* Error handling routine
*/
protected void sendError( int statusCode ) {
try { resp.sendError( statusCode ); } catch( Throwable x ) {};
}
/**
* Error handling routine
*/
protected void sendError( int statusCode, String message ) {
String statusText =
WebdavStatus.getStatusText(statusCode)+
(message != null
? ": "+Messages.format( message, (Object)null )
: "");
try { resp.sendError( statusCode, statusText ); } catch( Throwable x ) {};
}
/**
* Error handling routine
*/
protected void sendError( int statusCode, String message, Object[] args ) {
String statusText =
WebdavStatus.getStatusText(statusCode)+": "+
Messages.format( message, args );
try { resp.sendError( statusCode, statusText ); } catch( Throwable x ) {};
}
/**
* Error handling routine
*/
protected void sendError( int statusCode, Throwable t ) {
printStackTrace( t, statusCode );
String explanation = (t == null || t.getMessage() == null || "".equals(t.getMessage())
? Messages.format(t.getClass().getName(), (Object)null)
: t.getMessage()
);
String statusText =
WebdavStatus.getStatusText(statusCode)+": "+explanation;
try { resp.sendError( statusCode, statusText ); } catch( Throwable x ) {};
}
/**
* Prints the stack trace of the given exception if the specified status code
* is greater-or-equal the value of the servlet init-parameter printStackTrace.
* If the init-parameter is not specified, stack traces are printed for status
* codes >= 500.
*/
protected void printStackTrace( Throwable x, int statusCode ) {
int printStackTraceFrom = getIntInitParameter( "printStackTrace" );
if( printStackTraceFrom < 0 )
printStackTraceFrom = 500;
if( statusCode >= printStackTraceFrom )
x.printStackTrace();
}
/**
* Generate status text.
*
* @param parentElement the parent Element to append to.
* @param href Uri of the object
* @param statusCode HTTP status code of the error
*/
protected void generateStatusText(Element parentElement, String href, int statusCode) {
Element hrefElement = new Element(E_HREF, DNSP);
parentElement.addContent(hrefElement);
hrefElement.setText(getFullPath(href));
Element statusElement = new Element(E_STATUS, DNSP);
parentElement.addContent(statusElement);
statusElement.setText("HTTP/1.1 " + statusCode + " "
+ WebdavStatus.getStatusText(statusCode));
}
/**
* Generate an XML error message.
*
* @param macroException Nested exception
* @return String XML message
*/
protected String generateErrorMessage
(NestedSlideException nestedException) {
Element multistatus = new Element(E_MULTISTATUS, DNSP);
Enumeration nestedExceptionsList =
nestedException.enumerateExceptions();
while (nestedExceptionsList.hasMoreElements()) {
Element response = new Element(E_RESPONSE, DNSP);
multistatus.addContent(response);
SlideException ex =
(SlideException) nestedExceptionsList.nextElement();
generateStatusText(response, MethodUtil.getErrorMessage(ex),
getErrorCode(ex));
if (ex instanceof PreconditionViolationException) {
response.addContent(MethodUtil.getPreconditionViolationResponseDescription((PreconditionViolationException)ex));
}
}
StringWriter stringWriter = new StringWriter();
try {
new XMLOutputter().output(multistatus, stringWriter);
}
catch (IOException e) {
Domain.log(e);
}
return stringWriter.toString();
}
protected boolean exists( String uriStr ) throws SlideException {
// use a non-blocking slide token.
SlideToken stoken = readonlySlideToken();
boolean destinationExists = true;
try {
content.retrieve(stoken, uriStr);
}
catch (ObjectNotFoundException x) {
destinationExists = false;
}
return destinationExists;
}
protected boolean isLocked( String uriStr ) throws ServiceAccessException {
// use a non-blocking slide token.
SlideToken stoken = readonlySlideToken();
boolean isLocked = false;
try {
Enumeration locks = lock.enumerateLocks (stoken, uriStr, false);
while (locks.hasMoreElements()) {
if (lock.isLocked(stoken,(NodeLock) locks.nextElement(),false)) {
isLocked = true;
}
}
}
catch (ServiceAccessException x) {
throw x;
}
catch (SlideException x) {
// ignore silently
}
return isLocked;
}
protected boolean isLockNull( String uriStr ) throws ServiceAccessException {
// use a non-blocking slide token.
SlideToken stoken = readonlySlideToken();
boolean isLockNull = false;
try {
NodeRevisionDescriptor nrd =
content.retrieve(stoken, content.retrieve(stoken, uriStr));
isLockNull = isLockNull( nrd );
}
catch (ServiceAccessException x) {
throw x;
}
catch (SlideException x) {
// ignore silently
}
return isLockNull;
}
protected boolean isLockNull( NodeRevisionDescriptor nrd ) {
return nrd.propertyValueContains(P_RESOURCETYPE, E_LOCKNULL);
}
protected SlideToken readonlySlideToken() {
SlideToken stoken = slideToken;
if (stoken.isForceStoreEnlistment()) {
stoken = new SlideTokenWrapper(slideToken, false);
}
return stoken;
}
protected class RequestHeaders {
private static final int
ST_UNDEFINED = 0,
ST_INVALID = 1,
ST_DEFINED = 2;
// raw headers
private String hIfStr;
private String hLockTokenStr;
private String hDepthStr;
private String hDestinationStr;
private String hOverwriteStr;
private String hTimeoutStr;
private String hLabelStr;
// parsed headers
private List hIf;
private String hLockToken;
private int hDepth;
private String hDestination;
private boolean hOverwrite;
private int hTimeout;
private String hLabel;
// states
private int stIf = ST_UNDEFINED;
private int stLockToken = ST_UNDEFINED;
private int stDepth = ST_UNDEFINED;
private int stDestination = ST_UNDEFINED;
private int stOverwrite = ST_UNDEFINED;
private int stTimeout = ST_UNDEFINED;
private int stLabel = ST_UNDEFINED;
private RequestHeaders() {
}
protected boolean isDefined( String header ) {
return req.getHeader(header) != null;
}
protected List getIf() throws WebdavException {
if (stIf == ST_UNDEFINED) {
return Collections.EMPTY_LIST;
}
else if (stIf == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header If: "+hIfStr );
throw new WebdavException( sc );
}
else {
return hIf;
}
}
protected String getLockToken() throws WebdavException {
if (stLockToken == ST_UNDEFINED) {
return null;
}
else if (stLockToken == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header LockToken: "+hLockTokenStr );
throw new WebdavException( sc );
}
else {
return hLockToken;
}
}
protected int getDepth( int defaultValue ) throws WebdavException {
if (stDepth == ST_UNDEFINED) {
return defaultValue;
}
else if (stDepth == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header Depth: "+hDepthStr );
throw new WebdavException( sc );
}
else {
return hDepth;
}
}
protected String getDestination() throws WebdavException {
if (stDestination == ST_UNDEFINED) {
return null;
}
else if (stDestination == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header Destination: "+hDestinationStr );
throw new WebdavException( sc );
}
else {
return hDestination;
}
}
protected boolean getOverwrite( boolean defaultValue ) throws WebdavException {
if (stOverwrite == ST_UNDEFINED) {
return defaultValue;
}
else if (stOverwrite == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header Overwrite: "+hOverwriteStr );
throw new WebdavException( sc );
}
else {
return hOverwrite;
}
}
protected String getLabel() throws WebdavException {
if (stLabel == ST_UNDEFINED) {
return null;
}
else if (stLabel == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header Label: "+hLabelStr );
throw new WebdavException( sc );
}
else {
return hLabel;
}
}
protected int getTimeout( int defaultValue) throws WebdavException {
if (stTimeout == ST_UNDEFINED) {
return defaultValue;
}
else if (stTimeout == ST_INVALID) {
int sc = WebdavStatus.SC_PRECONDITION_FAILED;
sendError( sc, "Invalid header Timeout: "+hTimeoutStr );
throw new WebdavException( sc );
}
else {
return hTimeout;
}
}
private void parse() {
// If header
hIfStr = req.getHeader(H_IF);
if (hIfStr != null) {
stIf = ST_DEFINED;
try {
hIf = extractLockTokens(hIfStr);
}
catch (Exception e) {
stIf = ST_INVALID;
}
}
// Lock-Token header
hLockTokenStr = req.getHeader(H_LOCK_TOKEN);
if (hLockTokenStr != null) {
stLockToken = ST_DEFINED;
try {
List tl = extractLockTokens(hLockTokenStr);
hLockToken = (String)tl.get(0);
}
catch (Exception e) {
stLockToken = ST_INVALID;
}
}
// Depth header
hDepthStr = req.getHeader(H_DEPTH);
if (hDepthStr != null) {
stDepth = ST_DEFINED;
if ("0".equals(hDepthStr)) {
hDepth = 0;
}
else if ("1".equals(hDepthStr)) {
hDepth = 1;
}
else if ("infinity".equalsIgnoreCase(hDepthStr)) {
hDepth = INFINITY;
}
else {
stDepth = ST_INVALID;
hDepth = Integer.parseInt(hDepthStr);
}
}
// Destination header
hDestinationStr = req.getHeader(H_DESTINATION);
if (hDestinationStr != null) {
stDestination = ST_DEFINED;
hDestination = hDestinationStr;
}
// Overwrite header
String hOverwriteStr = req.getHeader(H_OVERWRITE);
if (hOverwriteStr != null) {
stOverwrite = ST_DEFINED;
if ("T".equalsIgnoreCase(hOverwriteStr)) {
hOverwrite = true;
}
else if ("F".equalsIgnoreCase(hOverwriteStr)) {
hOverwrite = false;
}
else {
stOverwrite = ST_INVALID;
}
}
// Timeout header
hTimeoutStr = req.getHeader(H_TIMEOUT);
if (hTimeoutStr != null) {
stTimeout = ST_DEFINED;
try {
hTimeout = extractLockDuration( hTimeoutStr );
}
catch (Exception e) {
stTimeout = ST_INVALID;
}
}
// Label header
hLabelStr = req.getHeader(H_LABEL);
if (hLabelStr != null) {
stLabel = ST_DEFINED;
hLabel = hLabelStr;
}
}
private List extractLockTokens(String hStr) {
List result = new ArrayList();
int pos = hStr.indexOf(S_LOCK_TOKEN);
int endPos = -1;
int offset = S_LOCK_TOKEN.length();
String lockToken = null;
while (pos != -1) {
endPos = hStr.indexOf('>', pos + offset);
if (endPos == -1) {
lockToken = hStr;
endPos = hStr.length();
} else {
lockToken = hStr.substring(pos + offset, endPos);
}
//System.out.println("Lock Token found :-" + lockToken + "-");
slideToken.addLockToken(lockToken);
result.add( lockToken );
pos = hStr.indexOf(S_LOCK_TOKEN, endPos);
}
return result;
}
private int extractLockDuration(String hStr) {
int result;
int firstCommaPos = hStr.indexOf(',');
if (firstCommaPos != -1) {
hStr = hStr.substring(0, firstCommaPos);
}
if (hStr.startsWith("Second-")) {
result = Integer.parseInt(hStr.substring("Second-".length()));
} else {
if (hStr.equalsIgnoreCase("Infinite")) {
result = INFINITY;
} else {
result = Integer.parseInt(hStr);
}
}
return result;
}
}
}