Package org.apache.slide.webdav.method

Source Code of org.apache.slide.webdav.method.AbstractWebdavMethod$RequestHeaders

/*
* $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;
        }
    }
}





TOP

Related Classes of org.apache.slide.webdav.method.AbstractWebdavMethod$RequestHeaders

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.