added SvnDAVServlet to scm-svn-plugin

This commit is contained in:
Sebastian Sdorra
2010-11-14 13:51:33 +01:00
parent 85c8cff734
commit da793d4481
101 changed files with 16896 additions and 0 deletions

View File

@@ -23,6 +23,12 @@
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit-dav</artifactId>
<version>1.3.4</version>
</dependency>
</dependencies>
</project>

View File

@@ -35,6 +35,8 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Singleton;
import sonia.scm.Type;
import sonia.scm.io.ExtendedCommand;
@@ -46,6 +48,7 @@ import java.io.File;
*
* @author Sebastian Sdorra
*/
@Singleton
public class SvnRepositoryHandler
extends AbstractSimpleRepositoryHandler<SvnConfig>
{

View File

@@ -0,0 +1,240 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import org.tmatesoft.svn.core.internal.server.dav.DAVConfig;
import org.tmatesoft.svn.core.internal.server.dav.SVNPathBasedAccess;
import sonia.scm.repository.SvnConfig;
/**
*
* @author Sebastian Sdorra
*/
public class SvnDAVConfig extends DAVConfig
{
/**
* Constructs ...
*
*
* @param davConfig
* @param config
*/
public SvnDAVConfig(DAVConfig davConfig, SvnConfig config)
{
this.davConfig = davConfig;
this.config = config;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public String getActivitiesDBPath()
{
return davConfig.getActivitiesDBPath();
}
/**
* Method description
*
*
* @return
*/
@Override
public String getRepositoryName()
{
return davConfig.getRepositoryName();
}
/**
* Method description
*
*
* @return
*/
@Override
public String getRepositoryParentPath()
{
return config.getRepositoryDirectory().getAbsolutePath();
}
/**
* Method description
*
*
* @return
*/
@Override
public String getRepositoryPath()
{
return davConfig.getRepositoryPath();
}
/**
* Method description
*
*
* @return
*/
@Override
public SVNPathBasedAccess getSVNAccess()
{
return davConfig.getSVNAccess();
}
/**
* Method description
*
*
* @return
*/
@Override
public String getXSLTIndex()
{
return davConfig.getXSLTIndex();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isAllowBulkUpdates()
{
return davConfig.isAllowBulkUpdates();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isAllowDepthInfinity()
{
return davConfig.isAllowDepthInfinity();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isAnonymousAllowed()
{
return davConfig.isAnonymousAllowed();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isAutoVersioning()
{
return davConfig.isAutoVersioning();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isListParentPath()
{
return davConfig.isListParentPath();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isNoAuthIfAnonymousAllowed()
{
return davConfig.isNoAuthIfAnonymousAllowed();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isUsingPBA()
{
return davConfig.isUsingPBA();
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isUsingRepositoryPathDirective()
{
return davConfig.isUsingRepositoryPathDirective();
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private SvnConfig config;
/** Field description */
private DAVConfig davConfig;
}

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.tmatesoft.svn.core.internal.server.dav.DAVConfig;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import sonia.scm.repository.SvnRepositoryHandler;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class SvnDAVServlet extends DAVServlet
{
/** Field description */
private static final long serialVersionUID = -1462257085465785945L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param handler
*/
@Inject
public SvnDAVServlet(SvnRepositoryHandler handler)
{
this.handler = handler;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected DAVConfig getDAVConfig()
{
return new SvnDAVConfig(super.getDAVConfig(), handler.getConfig());
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private SvnRepositoryHandler handler;
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.servlet.ServletModule;
import sonia.scm.web.filter.BasicAuthenticationFilter;
//~--- JDK imports ------------------------------------------------------------
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Sebastian Sdorra
*/
public class SvnServletModule extends ServletModule
{
/**
* Method description
*
*/
@Override
protected void configureServlets()
{
filter("/svn/*").through(BasicAuthenticationFilter.class);
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("SVNParentPath", System.getProperty("java.io.tmpdir"));
serve("/svn/*").with(SvnDAVServlet.class, parameters);
}
}

View File

@@ -29,6 +29,8 @@
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
@@ -72,5 +74,6 @@ public class SvnWebPlugin implements ScmWebPlugin
public void contextInitialized(ScmWebPluginContext context)
{
context.addScriptResource(new ClasspathWebResource(SCRIPT));
context.addInjectModule(new SvnServletModule());
}
}

View File

@@ -36,6 +36,7 @@
</prerequisites>
<modules>
<module>third-party</module>
<module>scm-core</module>
<module>scm-cli</module>
<module>scm-web-api</module>

View File

@@ -35,6 +35,9 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ConfigChangedListener;
import sonia.scm.SCMContextProvider;
import sonia.scm.util.Util;
@@ -60,6 +63,12 @@ public abstract class AbstractRepositoryHandler<C extends BasicRepositoryConfig>
implements RepositoryHandler
{
/** the logger for AbstractRepositoryHandler */
private static final Logger logger =
LoggerFactory.getLogger(AbstractRepositoryHandler.class);
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
@@ -120,6 +129,11 @@ public abstract class AbstractRepositoryHandler<C extends BasicRepositoryConfig>
{
if (configFile.exists())
{
if (logger.isDebugEnabled())
{
logger.debug("load config {}", configFile.getPath());
}
config = JAXB.unmarshal(configFile, getConfigClass());
}
}
@@ -144,6 +158,11 @@ public abstract class AbstractRepositoryHandler<C extends BasicRepositoryConfig>
{
if (config != null)
{
if (logger.isDebugEnabled())
{
logger.debug("store config {}", configFile.getPath());
}
JAXB.marshal(config, configFile);
}
}

22
third-party/pom.xml vendored Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>sonia.scm</groupId>
<artifactId>scm</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>sonia.scm.third-party</groupId>
<artifactId>sonia.scm.third-party</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>third-party</name>
<modules>
<module>svnkit-dav</module>
</modules>
</project>

34
third-party/svnkit-dav/pom.xml vendored Normal file
View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>sonia.scm.third-party</groupId>
<artifactId>sonia.scm.third-party</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit-dav</artifactId>
<packaging>jar</packaging>
<version>1.3.4</version>
<name>svnkit-dav</name>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit</artifactId>
<version>1.3.4</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,213 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.io.dav;
import java.util.Map;
import org.tmatesoft.svn.core.internal.io.dav.http.XMLReader;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVElement {
private static Map ourProperties = new SVNHashMap();
public static DAVElement getElement(String namespace, String name) {
if (namespace == null) {
namespace = "";
}
Map properties = (Map) ourProperties.get(namespace);
if (properties == null) {
properties = new SVNHashMap();
ourProperties.put(namespace, properties);
}
name = name.replace(XMLReader.COLON_REPLACEMENT, ':');
DAVElement property = (DAVElement) properties.get(name);
if (property == null) {
property = new DAVElement(namespace, name);
properties.put(name, property);
}
return property;
}
public static final String SVN_DAV_PROPERTY_NAMESPACE = "http://subversion.tigris.org/xmlns/dav/";
public static final String SVN_CUSTOM_PROPERTY_NAMESPACE = "http://subversion.tigris.org/xmlns/custom/";
public static final String SVN_SVN_PROPERTY_NAMESPACE = "http://subversion.tigris.org/xmlns/svn/";
public static final String SVN_APACHE_PROPERTY_NAMESPACE = "http://apache.org/dav/xmlns";
public static final String SVN_DAV_ERROR_NAMESPACE = "svn:";
public static final String DAV_NAMESPACE = "DAV:";
public static final String SVN_NAMESPACE = "svn:";
public static final String DEPTH_OPTION = SVN_DAV_PROPERTY_NAMESPACE + "svn/depth";
public static final String MERGE_INFO_OPTION = SVN_DAV_PROPERTY_NAMESPACE + "svn/mergeinfo";
public static final String LOG_REVPROPS_OPTION = SVN_DAV_PROPERTY_NAMESPACE + "svn/log-revprops";
public static final String PARTIAL_REPLAY_OPTION = SVN_DAV_PROPERTY_NAMESPACE + "svn/partial-replay";
public static final DAVElement ACTIVITY = getElement(DAV_NAMESPACE, "activity");
public static final DAVElement VERSION_HISTORY = getElement(DAV_NAMESPACE, "version-history");
public static final DAVElement DISPLAY_NAME = getElement(DAV_NAMESPACE, "displayname");
public static final DAVElement SUPPORTED_LIVE_PROPERTY = getElement(DAV_NAMESPACE, "supported-live-property");
public static final DAVElement MERGE_RESPONSE = getElement(DAV_NAMESPACE, "merge-response");
public static final DAVElement UPDATE_SET = getElement(DAV_NAMESPACE, "updated-set");
public static final DAVElement NO_AUTO_MERGE = getElement(DAV_NAMESPACE, "no-auto-merge");
public static final DAVElement NO_CHECKOUT = getElement(DAV_NAMESPACE, "no-checkout");
public static final DAVElement SOURCE = getElement(DAV_NAMESPACE, "source");
public static final DAVElement MULTISTATUS = getElement(DAV_NAMESPACE, "multistatus");
public static final DAVElement RESPONSE = getElement(DAV_NAMESPACE, "response");
public static final DAVElement RESPONSE_DESCRIPTION = getElement(DAV_NAMESPACE, "responsedescription");
public static final DAVElement HREF = getElement(DAV_NAMESPACE, "href");
public static final DAVElement PROPSTAT = getElement(DAV_NAMESPACE, "propstat");
public static final DAVElement PROP = getElement(DAV_NAMESPACE, "prop");
public static final DAVElement STATUS = getElement(DAV_NAMESPACE, "status");
public static final DAVElement BASELINE = getElement(DAV_NAMESPACE, "baseline");
public static final DAVElement BASELINE_COLLECTION = getElement(DAV_NAMESPACE, "baseline-collection");
public static final DAVElement CHECKED_IN = getElement(DAV_NAMESPACE, "checked-in");
public static final DAVElement COLLECTION = getElement(DAV_NAMESPACE, "collection");
public static final DAVElement RESOURCE_TYPE = getElement(DAV_NAMESPACE, "resourcetype");
public static final DAVElement VERSION_CONTROLLED_CONFIGURATION = getElement(DAV_NAMESPACE, "version-controlled-configuration");
public static final DAVElement VERSION_NAME = getElement(DAV_NAMESPACE, "version-name");
public static final DAVElement GET_CONTENT_LENGTH = getElement(DAV_NAMESPACE, "getcontentlength");
public static final DAVElement CREATION_DATE = getElement(DAV_NAMESPACE, "creationdate");
public static final DAVElement CREATOR_DISPLAY_NAME = getElement(DAV_NAMESPACE, "creator-displayname");
public static final DAVElement COMMENT = getElement(DAV_NAMESPACE, "comment");
public static final DAVElement DATE = getElement(SVN_NAMESPACE, "date");
public static final DAVElement POST_COMMIT_ERROR = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "post-commit-err");
public static final DAVElement PROPFIND = DAVElement.getElement(DAV_NAMESPACE, "propfind");
public static final DAVElement ALLPROP = DAVElement.getElement(DAV_NAMESPACE, "allprop");
public static final DAVElement PROPNAME = DAVElement.getElement(DAV_NAMESPACE, "propname");
public static final DAVElement ACTIVE_LOCK = DAVElement.getElement(DAV_NAMESPACE, "activelock");
public static final DAVElement LOCK_TYPE = DAVElement.getElement(DAV_NAMESPACE, "locktype");
public static final DAVElement LOCK_SCOPE = DAVElement.getElement(DAV_NAMESPACE, "lockscope");
public static final DAVElement WRITE = DAVElement.getElement(DAV_NAMESPACE, "write");
public static final DAVElement EXCLUSIVE = DAVElement.getElement(DAV_NAMESPACE, "exclusive");
public static final DAVElement SHARED = DAVElement.getElement(DAV_NAMESPACE, "shared");
public static final DAVElement DEPTH = DAVElement.getElement(DAV_NAMESPACE, "depth");
public static final DAVElement SUPPORTED_LOCK = getElement(DAV_NAMESPACE, "supportedlock");
public static final DAVElement LOCK_DISCOVERY = getElement(DAV_NAMESPACE, "lockdiscovery");
public static final DAVElement LOCK_OWNER = getElement(DAV_NAMESPACE, "owner");
public static final DAVElement LOCK_TIMEOUT = getElement(DAV_NAMESPACE, "timeout");
public static final DAVElement LOCK_TOKEN = getElement(DAV_NAMESPACE, "locktoken");
public static final DAVElement LOCK_ENTRY = getElement(DAV_NAMESPACE, "lockentry");
public static final DAVElement SVN_LOCK_TOKEN_LIST = getElement(SVN_NAMESPACE, "lock-token-list");
public static final DAVElement SVN_LOCK = getElement(SVN_NAMESPACE, "lock");
public static final DAVElement SVN_LOCK_PATH = getElement(SVN_NAMESPACE, "path");
public static final DAVElement SVN_LOCK_TOKEN = getElement(SVN_NAMESPACE, "token");
public static final DAVElement SVN_LOCK_COMMENT = getElement(SVN_NAMESPACE, "comment");
public static final DAVElement SVN_LOCK_OWNER = getElement(SVN_NAMESPACE, "owner");
public static final DAVElement SVN_LOCK_CREATION_DATE = getElement(SVN_NAMESPACE, "creationdate");
public static final DAVElement SVN_LOCK_EXPIRATION_DATE = getElement(SVN_NAMESPACE, "expirationdate");
//servlet defined svn namespace properties
public static final DAVElement PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "path");
public static final DAVElement REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "revision");
public static final DAVElement START_REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "start-revision");
public static final DAVElement END_REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "end-revision");
public static final DAVElement PEG_REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "peg-revision");
public static final DAVElement INCLUDE_MERGED_REVISIONS = getElement(SVN_NAMESPACE, "include-merged-revisions");
public static final DAVElement BASELINE_RELATIVE_PATH = getElement(SVN_DAV_PROPERTY_NAMESPACE, "baseline-relative-path");
public static final DAVElement REPOSITORY_UUID = getElement(SVN_DAV_PROPERTY_NAMESPACE, "repository-uuid");
public static final DAVElement MD5_CHECKSUM = getElement(SVN_DAV_PROPERTY_NAMESPACE, "md5-checksum");
public static final DAVElement DEADPROP_COUNT = getElement(SVN_DAV_PROPERTY_NAMESPACE, "deadprop-count");
public static final DAVElement AUTO_VERSION = getElement(DAV_NAMESPACE, "auto-version");
public static final DAVElement MERGE_INFO_ITEM = getElement(SVN_NAMESPACE, "mergeinfo-item");
public static final DAVElement MERGE_INFO_PATH = getElement(SVN_NAMESPACE, "mergeinfo-path");
public static final DAVElement MERGE_INFO_INFO = getElement(SVN_NAMESPACE, "mergeinfo-info");
//Supported live properties
public static final DAVElement GET_CONTENT_LANGUAGE = getElement(DAV_NAMESPACE, "getcontentlanguage");
public static final DAVElement GET_CONTENT_TYPE = getElement(DAV_NAMESPACE, "getcontenttype");
public static final DAVElement GET_ETAG = getElement(DAV_NAMESPACE, "getetag");
public static final DAVElement GET_LAST_MODIFIED = getElement(DAV_NAMESPACE, "getlastmodified");
public static final DAVElement[] STARTING_PROPERTIES = {VERSION_CONTROLLED_CONFIGURATION, RESOURCE_TYPE, BASELINE_RELATIVE_PATH, REPOSITORY_UUID};
public static final DAVElement[] BASELINE_PROPERTIES = {BASELINE_COLLECTION, VERSION_NAME};
private String myPropertyName;
private String myNamespace;
public static final DAVElement LOG = getElement(SVN_SVN_PROPERTY_NAMESPACE, "log");
private DAVElement(String namespace, String propertyName) {
myNamespace = namespace;
myPropertyName = propertyName;
}
public String getNamespace() {
return myNamespace;
}
public String getName() {
return myPropertyName;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getNamespace());
if (!getNamespace().endsWith(":")) {
sb.append(":");
}
sb.append(getName());
return sb.toString();
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((myNamespace == null) ? 0 : myNamespace.hashCode());
result = prime * result + ((myPropertyName == null) ? 0 : myPropertyName.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DAVElement other = (DAVElement) obj;
if (myNamespace == null) {
if (other.myNamespace != null) {
return false;
}
} else if (!myNamespace.equals(other.myNamespace)) {
return false;
}
if (myPropertyName == null) {
if (other.myPropertyName != null) {
return false;
}
} else if (!myPropertyName.equals(other.myPropertyName)) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,418 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.io.fs;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import org.tmatesoft.svn.core.ISVNCanceller;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.delta.SVNDeltaCombiner;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNUUIDGenerator;
import org.tmatesoft.svn.core.internal.wc.IOExceptionWrapper;
import org.tmatesoft.svn.core.internal.wc.ISVNCommitPathHandler;
import org.tmatesoft.svn.core.internal.wc.SVNCommitUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class FSRepositoryUtil {
public static final int MAX_KEY_SIZE = 200;
private static final byte[] ourCopyBuffer = new byte[1024*16];
public static String generateLockToken() throws SVNException {
String uuid = SVNUUIDGenerator.formatUUID(SVNUUIDGenerator.generateUUID());
return FSFS.SVN_OPAQUE_LOCK_TOKEN + uuid;
}
public static void replay(FSFS fsfs, FSRoot root, String basePath, long lowRevision, boolean sendDeltas, ISVNEditor editor) throws SVNException {
Map fsChanges = root.getChangedPaths();
basePath = basePath.startsWith("/") ? basePath.substring(1) : basePath;
Collection interestingPaths = new LinkedList();
Map changedPaths = new SVNHashMap();
for (Iterator paths = fsChanges.keySet().iterator(); paths.hasNext();) {
String path = (String) paths.next();
FSPathChange change = (FSPathChange) fsChanges.get(path);
path = path.startsWith("/") ? path.substring(1) : path;
if (SVNPathUtil.isWithinBasePath(basePath, path)) {
interestingPaths.add(path);
changedPaths.put(path, change);
} else if (SVNPathUtil.isWithinBasePath(path, basePath)) {
interestingPaths.add(path);
changedPaths.put(path, change);
}
}
if (FSRepository.isInvalidRevision(lowRevision)) {
lowRevision = 0;
}
FSRoot compareRoot = null;
if (sendDeltas) {
long revision = -1;
if (root instanceof FSRevisionRoot) {
FSRevisionRoot revRoot = (FSRevisionRoot) root;
revision = revRoot.getRevision() - 1;
} else if (root instanceof FSTransactionRoot) {
FSTransactionRoot txnRoot = (FSTransactionRoot) root;
revision = txnRoot.getTxn().getBaseRevision();
}
compareRoot = fsfs.createRevisionRoot(revision);
}
if (root instanceof FSRevisionRoot) {
FSRevisionRoot revRoot = (FSRevisionRoot) root;
editor.targetRevision(revRoot.getRevision());
}
ISVNCommitPathHandler handler = new FSReplayPathHandler(fsfs, root, compareRoot, changedPaths, basePath, lowRevision);
SVNCommitUtil.driveCommitEditor(handler, interestingPaths, editor, -1);
}
public synchronized static void copy(InputStream src, OutputStream dst, ISVNCanceller canceller) throws SVNException {
try {
while (true) {
if (canceller != null) {
canceller.checkCancelled();
}
int length = src.read(ourCopyBuffer);
if (length > 0) {
dst.write(ourCopyBuffer, 0, length);
}
if (length < 0) {
break;
}
}
} catch (IOExceptionWrapper ioew) {
throw ioew.getOriginalException();
} catch (IOException ioe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
SVNErrorManager.error(err, ioe, SVNLogType.FSFS);
}
}
public static boolean arePropertiesEqual(FSRevisionNode revNode1, FSRevisionNode revNode2) {
return areRepresentationsEqual(revNode1, revNode2, true);
}
public static boolean arePropertiesChanged(FSRoot root1, String path1, FSRoot root2, String path2) throws SVNException {
FSRevisionNode node1 = root1.getRevisionNode(path1);
FSRevisionNode node2 = root2.getRevisionNode(path2);
return !areRepresentationsEqual(node1, node2, true);
}
public static boolean areFileContentsChanged(FSRoot root1, String path1, FSRoot root2, String path2) throws SVNException {
if (root1.checkNodeKind(path1) != SVNNodeKind.FILE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, "''{0}'' is not a file", path1);
SVNErrorManager.error(err, SVNLogType.FSFS);
}
if (root2.checkNodeKind(path2) != SVNNodeKind.FILE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, "''{0}'' is not a file", path2);
SVNErrorManager.error(err, SVNLogType.FSFS);
}
FSRevisionNode revNode1 = root1.getRevisionNode(path1);
FSRevisionNode revNode2 = root2.getRevisionNode(path2);
return !areRepresentationsEqual(revNode1, revNode2, false);
}
public static SVNProperties getPropsDiffs(SVNProperties sourceProps, SVNProperties targetProps){
SVNProperties result = new SVNProperties();
if(sourceProps == null){
sourceProps = new SVNProperties();
}
if(targetProps == null){
targetProps = new SVNProperties();
}
for(Iterator names = sourceProps.nameSet().iterator(); names.hasNext();){
String propName = (String) names.next();
SVNPropertyValue srcPropVal = sourceProps.getSVNPropertyValue(propName);
SVNPropertyValue targetPropVal = targetProps.getSVNPropertyValue(propName);
if (targetPropVal == null) {
result.put(propName, targetPropVal);
} else if (!targetPropVal.equals(srcPropVal)) {
result.put(propName, targetPropVal);
}
}
for(Iterator names = targetProps.nameSet().iterator(); names.hasNext();){
String propName = (String)names.next();
SVNPropertyValue targetPropVal = targetProps.getSVNPropertyValue(propName);
SVNPropertyValue sourceValue = sourceProps.getSVNPropertyValue(propName);
if (sourceValue == null){
result.put(propName, targetPropVal);
}
}
return result;
}
public static boolean checkFilesDifferent(FSRoot root1, String path1, FSRoot root2,
String path2, SVNDeltaCombiner deltaCombiner) throws SVNException {
boolean changed = FSRepositoryUtil.areFileContentsChanged(root1, path1, root2, path2);
if (!changed) {
return false;
}
FSRevisionNode revNode1 = root1.getRevisionNode(path1);
FSRevisionNode revNode2 = root2.getRevisionNode(path2);
if (revNode1.getFileLength() != revNode2.getFileLength()) {
return true;
}
if (!revNode1.getFileMD5Checksum().equals(revNode2.getFileMD5Checksum())) {
return true;
}
InputStream file1IS = null;
InputStream file2IS = null;
try {
file1IS = root1.getFileStreamForPath(deltaCombiner, path1);
file2IS = root2.getFileStreamForPath(deltaCombiner, path2);
int r1 = -1;
int r2 = -1;
while (true) {
r1 = file1IS.read();
r2 = file2IS.read();
if (r1 != r2) {
return true;
}
if (r1 == -1) {// we've finished - files do not differ
break;
}
}
} catch (IOException ioe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage());
SVNErrorManager.error(err, ioe, SVNLogType.FSFS);
} finally {
SVNFileUtil.closeFile(file1IS);
SVNFileUtil.closeFile(file2IS);
}
return false;
}
public static void sendTextDelta(ISVNEditor editor, String editPath, String sourcePath,
String hexDigest, FSRevisionRoot sourceRoot, String targetPath,
FSRevisionRoot targetRoot, boolean sendDeltas, SVNDeltaCombiner deltaCombiner,
SVNDeltaGenerator deltaGenerator, FSFS fsfs) throws SVNException {
editor.applyTextDelta(editPath, hexDigest);
if (sendDeltas) {
InputStream sourceStream = null;
InputStream targetStream = null;
try {
if (sourceRoot != null && sourcePath != null) {
sourceStream = sourceRoot.getFileStreamForPath(deltaCombiner, sourcePath);
} else {
sourceStream = FSInputStream.createDeltaStream(deltaCombiner, (FSRevisionNode) null, fsfs);
}
targetStream = targetRoot.getFileStreamForPath(deltaCombiner, targetPath);
deltaGenerator.sendDelta(editPath, sourceStream, 0, targetStream, editor, false);
} finally {
SVNFileUtil.closeFile(sourceStream);
SVNFileUtil.closeFile(targetStream);
}
} else {
editor.textDeltaChunk(editPath, SVNDiffWindow.EMPTY);
editor.textDeltaEnd(editPath);
}
}
public static void loadRootChangesOffset(FSFS fsfs, long revision, FSFile file, long[] rootOffset, long[] changesOffset) throws SVNException {
ByteBuffer buffer = ByteBuffer.allocate(64);
long offset = 0;
if (fsfs.isPackedRevision(revision) && ((revision + 1) % fsfs.getMaxFilesPerDirectory()) != 0) {
offset = fsfs.getPackedOffset(revision + 1);
} else {
offset = file.size();
}
long revOffset = 0;
if (fsfs.isPackedRevision(revision)) {
revOffset = fsfs.getPackedOffset(revision);
}
file.seek(offset - 64);
try {
file.read(buffer);
} catch (IOException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getMessage());
SVNErrorManager.error(err, e, SVNLogType.FSFS);
}
buffer.flip();
if (buffer.get(buffer.limit() - 1) != '\n') {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_CORRUPT,
"Revision file lacks trailing newline");
SVNErrorManager.error(err, SVNLogType.FSFS);
}
int spaceIndex = -1;
int eolIndex = -1;
for (int i = buffer.limit() - 2; i >= 0; i--) {
byte b = buffer.get(i);
if (b == ' ' && spaceIndex < 0) {
spaceIndex = i;
} else if (b == '\n' && eolIndex < 0) {
eolIndex = i;
break;
}
}
if (eolIndex < 0) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_CORRUPT,
"Final line in revision file longer than 64 characters");
SVNErrorManager.error(err, SVNLogType.FSFS);
}
if (spaceIndex < 0) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_CORRUPT,
"Final line in revision file missing space");
SVNErrorManager.error(err, SVNLogType.FSFS);
}
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
try {
buffer.limit(buffer.limit() - 1);
buffer.position(spaceIndex + 1);
String line = decoder.decode(buffer).toString();
if (changesOffset != null && changesOffset.length > 0) {
changesOffset[0] = revOffset + Long.parseLong(line);
}
buffer.limit(spaceIndex);
buffer.position(eolIndex + 1);
line = decoder.decode(buffer).toString();
if (rootOffset != null && rootOffset.length > 0) {
rootOffset[0] = revOffset + Long.parseLong(line);
}
} catch (NumberFormatException nfe) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_CORRUPT,
"Final line in revision file missing changes and root offsets");
SVNErrorManager.error(err, nfe, SVNLogType.FSFS);
} catch (CharacterCodingException e) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_CORRUPT,
"Final line in revision file missing changes and root offsets");
SVNErrorManager.error(err, e, SVNLogType.FSFS);
}
}
public static String generateNextKey(String oldKey) throws SVNException {
char[] nextKey = new char[oldKey.length() + 1];
boolean carry = true;
if (oldKey.length() > 1 && oldKey.charAt(0) == '0') {
return null;
}
for (int i = oldKey.length() - 1; i >= 0; i--) {
char c = oldKey.charAt(i);
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))) {
return null;
}
if (carry) {
if (c == 'z') {
nextKey[i] = '0';
} else {
carry = false;
if (c == '9') {
nextKey[i] = 'a';
} else {
nextKey[i] = (char) (c + 1);
}
}
} else {
nextKey[i] = c;
}
}
int nextKeyLength = oldKey.length() + (carry ? 1 : 0);
if (nextKeyLength >= MAX_KEY_SIZE) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN,
"FATAL error: new key length is greater than the threshold {0}",
new Integer(MAX_KEY_SIZE));
SVNErrorManager.error(err, SVNLogType.FSFS);
}
if (carry) {
System.arraycopy(nextKey, 0, nextKey, 1, oldKey.length());
nextKey[0] = '1';
}
return new String(nextKey, 0, nextKeyLength);
}
public static void checkReposDBFormat(int format) throws SVNException {
if (format < FSFS.DB_FORMAT_LOW || format > FSFS.DB_FORMAT) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_UNSUPPORTED_FORMAT,
"Expected FS format between ''{0}'' and ''{1}''; found format ''{2}''",
new Object[] {new Integer(FSFS.DB_FORMAT_LOW), new Integer(FSFS.DB_FORMAT),
new Integer(format)});
SVNErrorManager.error(err, SVNLogType.FSFS);
}
}
public static void validateProperty(String propertyName, SVNPropertyValue propertyValue) throws SVNException {
if (!SVNProperty.isRegularProperty(propertyName)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.REPOS_BAD_ARGS,
"Storage of non-regular property ''{0}'' is disallowed through the repository interface, and could indicate a bug in your client", propertyName);
SVNErrorManager.error(err, SVNLogType.FSFS);
}
if (SVNProperty.isSVNProperty(propertyName) && propertyValue != null) {
if (SVNRevisionProperty.DATE.equals(propertyName)) {
try {
SVNDate.parseDateString(propertyValue.getString());
} catch (SVNException svne) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.BAD_PROPERTY_VALUE);
SVNErrorManager.error(err, SVNLogType.FSFS);
}
}
}
}
private static boolean areRepresentationsEqual(FSRevisionNode revNode1, FSRevisionNode revNode2, boolean forProperties) {
if(revNode1 == revNode2){
return true;
}else if(revNode1 == null || revNode2 == null){
return false;
}
return FSRepresentation.compareRepresentations(forProperties ? revNode1.getPropsRepresentation() : revNode1.getTextRepresentation(), forProperties ? revNode2.getPropsRepresentation() : revNode2.getTextRepresentation());
}
}

View File

@@ -0,0 +1,31 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVActivityResourceHelper extends DAVResourceHelper {
protected void prepare(DAVResource resource) throws DAVException {
String txnName = DAVServletUtil.getTxn(resource.getActivitiesDB(), resource.getResourceURI().getActivityID());
resource.setTxnName(txnName);
resource.setExists(txnName != null);
}
protected DAVResource getParentResource(DAVResource resource) throws DAVException {
return DAVPrivateResourceHelper.createPrivateResource(resource, DAVResourceKind.ACT_COLLECTION);
}
}

View File

@@ -0,0 +1,27 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVAutoVersion {
public static DAVAutoVersion NEVER = new DAVAutoVersion();
public static DAVAutoVersion ALWAYS = new DAVAutoVersion();
public static DAVAutoVersion LOCKED = new DAVAutoVersion();
private DAVAutoVersion() {
}
}

View File

@@ -0,0 +1,186 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.File;
import javax.servlet.ServletConfig;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVConfig {
private static final String PATH_DIRECIVE = "SVNPath";
private static final String PARENT_PATH_DIRECIVE = "SVNParentPath";
private static final String SVN_ACCESS_FILE_DIRECTIVE = "AuthzSVNAccessFile";
private static final String SVN_ANONYMOUS_DIRECTIVE = "AuthzSVNAnonymous";
private static final String SVN_NO_AUTH_IF_ANONYMOUS_ALLOWED_DIRECIVE = "AuthzSVNNoAuthWhenAnonymousAllowed";
private static final String LIST_PARENT_PATH_DIRECTIVE = "SVNListParentPath";
private static final String REPOS_NAME = "SVNReposName";
private static final String XSLT_INDEX = "SVNIndexXSLT";
private static final String ACTIVITIES_DB = "SVNActivitiesDB";
private static final String AUTOVERSIONING = "SVNAutoversioning";
private static final String ALLOW_BULK_UPDATES = "SVNAllowBulkUpdates";
private static final String DAV_DEPTH = "DAVDepthInfinity";
private static final String OFF = "off";
private static final String ON = "on";
private String myRepositoryPath;
private String myRepositoryParentPath;
private String myRepositoryName;
private String myXSLTIndex;
private String myActivitiesDBPath;
private SVNPathBasedAccess mySVNAccess = null;
private boolean myUsingPBA = false;
private boolean myAnonymous = true;
private boolean myNoAuthIfAnonymousAllowed = false;
private boolean myIsListParentPath = false;
private boolean myIsAutoVersioning = false;
private boolean myIsAllowBulkUpdates = false;
private boolean myIsAllowDepthInfinity = false;
// scm-manager change
public DAVConfig()
{
}
public DAVConfig(ServletConfig servletConfig) throws SVNException {
String repositoryPath = servletConfig.getInitParameter(PATH_DIRECIVE);
String repositoryParentPath = servletConfig.getInitParameter(PARENT_PATH_DIRECIVE);
myRepositoryName = servletConfig.getInitParameter(REPOS_NAME);
myXSLTIndex = servletConfig.getInitParameter(XSLT_INDEX);
if (repositoryPath != null && repositoryParentPath == null) {
myRepositoryPath = repositoryPath;
myRepositoryParentPath = null;
} else if (repositoryParentPath != null && repositoryPath == null) {
myRepositoryParentPath = repositoryParentPath;
myRepositoryPath = null;
} else {
//repositoryPath == null <=> repositoryParentPath == null.
if (repositoryPath == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE,
"Neither SVNPath nor SVNParentPath directive were specified."), SVNLogType.NETWORK);
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE,
"Only one of SVNPath and SVNParentPath directives should be specified."), SVNLogType.NETWORK);
}
}
String configurationFilePath = servletConfig.getInitParameter(SVN_ACCESS_FILE_DIRECTIVE);
if (configurationFilePath != null) {
myUsingPBA = true;
try {
mySVNAccess = new SVNPathBasedAccess(new File(configurationFilePath));
} catch (SVNException e) {
mySVNAccess = null;
}
}
String anonymous = servletConfig.getInitParameter(SVN_ANONYMOUS_DIRECTIVE);
if (anonymous != null && OFF.equals(anonymous)) {
myAnonymous = false;
}
String noAuthIfAnonymousAllowed = servletConfig.getInitParameter(SVN_NO_AUTH_IF_ANONYMOUS_ALLOWED_DIRECIVE);
if (noAuthIfAnonymousAllowed != null && ON.equals(noAuthIfAnonymousAllowed)) {
myNoAuthIfAnonymousAllowed = true;
}
String listParentPath = servletConfig.getInitParameter(LIST_PARENT_PATH_DIRECTIVE);
if (listParentPath != null && ON.equals(listParentPath)) {
myIsListParentPath = true;
}
String autoversioning = servletConfig.getInitParameter(AUTOVERSIONING);
if (autoversioning != null && ON.equals(autoversioning)) {
myIsAutoVersioning = true;
}
String allowBulkUpdates = servletConfig.getInitParameter(ALLOW_BULK_UPDATES);
if (allowBulkUpdates != null && ON.equals(allowBulkUpdates)) {
myIsAllowBulkUpdates = true;
}
String allowDepthInfinity = servletConfig.getInitParameter(DAV_DEPTH);
if (allowDepthInfinity != null && ON.equals(allowDepthInfinity)) {
myIsAllowDepthInfinity = true;
}
myActivitiesDBPath = servletConfig.getInitParameter(ACTIVITIES_DB);
}
public boolean isAllowDepthInfinity() {
return myIsAllowDepthInfinity;
}
public String getRepositoryName() {
return myRepositoryName;
}
public String getXSLTIndex() {
return myXSLTIndex;
}
public boolean isUsingRepositoryPathDirective() {
return myRepositoryPath != null;
}
public String getRepositoryPath() {
return myRepositoryPath;
}
public String getRepositoryParentPath() {
return myRepositoryParentPath;
}
public SVNPathBasedAccess getSVNAccess() {
return mySVNAccess;
}
public boolean isUsingPBA() {
return myUsingPBA;
}
public boolean isAnonymousAllowed() {
return myAnonymous;
}
public boolean isNoAuthIfAnonymousAllowed() {
return myNoAuthIfAnonymousAllowed;
}
public boolean isListParentPath() {
return myIsListParentPath;
}
public String getActivitiesDBPath() {
return myActivitiesDBPath;
}
public boolean isAutoVersioning() {
return myIsAutoVersioning;
}
public boolean isAllowBulkUpdates() {
return myIsAllowBulkUpdates;
}
}

View File

@@ -0,0 +1,67 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVDepth {
public static final DAVDepth DEPTH_ZERO = new DAVDepth(0, "0");
public static final DAVDepth DEPTH_ONE = new DAVDepth(1, "1");
public static final DAVDepth DEPTH_INFINITY = new DAVDepth(Integer.MAX_VALUE, "infinity");
private int myID;
private String myName;
private DAVDepth(int id, String name) {
myID = id;
myName = name;
}
public int getID() {
return myID;
}
public String toString() {
return myName;
}
public static DAVDepth parseDepth(String depth) {
if (DAVDepth.DEPTH_INFINITY.toString().equalsIgnoreCase(depth)) {
return DAVDepth.DEPTH_INFINITY;
} else if (DAVDepth.DEPTH_ZERO.toString().equalsIgnoreCase(depth)) {
return DAVDepth.DEPTH_ZERO;
} else if (DAVDepth.DEPTH_ONE.toString().equalsIgnoreCase(depth)) {
return DAVDepth.DEPTH_ONE;
}
return null;
}
public static DAVDepth decreaseDepth(DAVDepth currentDepth) throws SVNException {
if (currentDepth == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_MALFORMED_DATA, "Depth is not specified."), SVNLogType.NETWORK);
}
if (currentDepth == DEPTH_ZERO || currentDepth == DEPTH_INFINITY) {
return currentDepth;
}
return DAVDepth.DEPTH_ZERO;
}
}

View File

@@ -0,0 +1,43 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVErrorCode {
public static final int IF_PARSE = 100;
public static final int IF_MULTIPLE_NOT = 101;
public static final int IF_UNK_CHAR = 102;
public static final int IF_ABSENT = 103;
public static final int IF_TAGGED = 104;
public static final int IF_UNCLOSED_PAREN = 105;
public static final int PROP_BAD_MAJOR = 200;
public static final int PROP_READONLY = 201;
public static final int PROP_NO_DATABASE = 202;
public static final int PROP_NOT_FOUND = 203;
public static final int PROP_BAD_LOCKDB = 204;
public static final int PROP_OPENING = 205;
public static final int PROP_EXEC = 206;
public static final int LOCK_OPENDB = 400;
public static final int LOCK_NODB = 401;
public static final int CORRUPT_DB = 402;
public static final int UNK_STATE_TOKEN = 403;
public static final int PARSE_TOKEN = 404;
public static final int LOCK_SAVE_LOCK = 405;
}

View File

@@ -0,0 +1,160 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.text.MessageFormat;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVResponse;
import org.tmatesoft.svn.core.internal.server.dav.handlers.ServletDAVHandler;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.1.2
* @author TMate Software Ltd.
*/
public class DAVException extends SVNException {
private static final long serialVersionUID = 4845L;
private String myMessage;
private int myResponseCode;
private int myErrorID;
private DAVException myPreviousException;
private String myTagName;
private String myNameSpace;
private DAVResponse myResponse;
public DAVException(String message, Object[] objects, int responseCode, SVNErrorMessage error, SVNLogType logType, Level level,
DAVException previousException, String tagName, String nameSpace, int errorID, DAVResponse response) {
super(error != null ? error : SVNErrorMessage.create(SVNErrorCode.UNKNOWN));
myMessage = objects == null ? message : MessageFormat.format(message, objects);
myResponseCode = responseCode;
myPreviousException = previousException;
myTagName = tagName;
myNameSpace = nameSpace;
myErrorID = errorID;
myResponse = response;
SVNDebugLog.getDefaultLog().log(logType, message, level);
}
public DAVException(String message, int respondCode, DAVException previousException, int errorID) {
this(message, null, respondCode, null, SVNLogType.NETWORK, Level.FINE, previousException, null, null, errorID, null);
}
public DAVException(String message, Object[] objects, int respondCode, DAVException previousException, int errorID) {
this(message, objects, respondCode, null, SVNLogType.NETWORK, Level.FINE, previousException, null, null, errorID, null);
}
public DAVException(String message, int responseCode, SVNLogType logType) {
this(message, null, responseCode, null, logType, Level.FINE, null, null, null, 0, null);
}
public DAVException(String message, int responseCode, SVNLogType logType, DAVResponse response) {
this(message, null, responseCode, null, logType, Level.FINE, null, null, null, 0, response);
}
public DAVException(String message, int responseCode, SVNLogType logType, String tagName, String nameSpace) {
this(message, null, responseCode, null, logType, Level.FINE, null, tagName, nameSpace, 0, null);
}
public DAVException(String message, Object[] objects, int responseCode, int errorID) {
this(message, objects, responseCode, null, SVNLogType.NETWORK, Level.FINE, null, null, null, errorID, null);
}
public DAVException(String message, Object[] objects, int responseCode, int errorID, DAVResponse response) {
this(message, objects, responseCode, null, SVNLogType.NETWORK, Level.FINE, null, null, null, errorID, response);
}
public DAVException(String message, int responseCode, int errorID) {
this(message, null, responseCode, errorID);
}
public DAVException(String message, int responseCode, int errorID, DAVResponse response) {
this(message, null, responseCode, errorID, response);
}
public int getErrorID() {
return myErrorID;
}
public String getTagName() {
return myTagName;
}
public int getResponseCode() {
return myResponseCode;
}
public String getMessage() {
return myMessage;
}
public DAVException getPreviousException() {
return myPreviousException;
}
public String getNameSpace() {
return myNameSpace;
}
public DAVResponse getResponse() {
return myResponse;
}
public void setResponse(DAVResponse response) {
myResponse = response;
}
public void setPreviousException(DAVException previousException) {
myPreviousException = previousException;
}
public static DAVException convertError(SVNErrorMessage err, int statusCode, String message, Object[] objects) {
if (err.getErrorCode() == SVNErrorCode.FS_NOT_FOUND) {
statusCode = HttpServletResponse.SC_NOT_FOUND;
} else if (err.getErrorCode() == SVNErrorCode.UNSUPPORTED_FEATURE) {
statusCode = HttpServletResponse.SC_NOT_IMPLEMENTED;
} else if (err.getErrorCode() == SVNErrorCode.FS_PATH_ALREADY_LOCKED) {
statusCode = ServletDAVHandler.SC_HTTP_LOCKED;
}
DAVException error = buildErrorChain(err, statusCode);
if (message != null && err.getErrorCode() != SVNErrorCode.REPOS_HOOK_FAILURE) {
if (objects != null) {
message = MessageFormat.format(message, objects);
}
error = new DAVException(message, null, statusCode, null, SVNLogType.NETWORK, Level.FINE, error, null, null,
err.getErrorCode().getCode(), null);
}
return error;
}
private static DAVException buildErrorChain(SVNErrorMessage err, int statusCode) {
DAVException error = new DAVException(err.getMessage(), null, statusCode, err, SVNLogType.NETWORK, Level.FINE, null,
DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE, err.getErrorCode().getCode(), null);
if (err.getChildErrorMessage() != null) {
error.setPreviousException(buildErrorChain(err.getChildErrorMessage(), statusCode));
}
return error;
}
}

View File

@@ -0,0 +1,29 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVHistoryResourceHelper extends DAVResourceHelper {
protected void prepare(DAVResource resource) throws DAVException {
}
public DAVResource getParentResource(DAVResource resource) throws DAVException {
DAVResourceHelper.throwIllegalGetParentResourceError(resource);
return null;
}
}

View File

@@ -0,0 +1,52 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.util.LinkedList;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVIFHeader {
private String myURI;
private LinkedList myStateList;
private boolean myIsDummyHeader;
public DAVIFHeader(String uri) {
this(uri, false);
}
public DAVIFHeader(String uri, boolean isDummy) {
myURI = uri;
myStateList = new LinkedList();
myIsDummyHeader = isDummy;
}
public void addIFState(DAVIFState ifState) {
myStateList.addFirst(ifState);
}
public boolean isDummyHeader() {
return myIsDummyHeader;
}
public String getURI() {
return myURI;
}
public LinkedList getStateList() {
return myStateList;
}
}

View File

@@ -0,0 +1,52 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVIFState {
public static final int IF_CONDITION_NORMAL = 0;
public static final int IF_CONDITION_NOT = 1;
private DAVIFStateType myType;
private String myETag;
private String myLockToken;
private int myCondition;
public DAVIFState(int condition, String tag, String lockToken, DAVIFStateType type) {
myCondition = condition;
myETag = tag;
myType = type;
myLockToken = lockToken;
}
public DAVIFStateType getType() {
return myType;
}
public String getLockToken() {
return myLockToken;
}
public String getETag() {
return myETag;
}
public int getCondition() {
return myCondition;
}
}

View File

@@ -0,0 +1,26 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVIFStateType {
public static final DAVIFStateType IF_ETAG = new DAVIFStateType();
public static final DAVIFStateType IF_OPAQUE_LOCK = new DAVIFStateType();
public static final DAVIFStateType IF_UNKNOWN = new DAVIFStateType();
private DAVIFStateType() {
}
}

View File

@@ -0,0 +1,81 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.util.Date;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVLock {
private DAVLockRecType myRecType;
private DAVLockScope myScope;
private DAVLockType myType;
private boolean myIsLockNull;
private DAVDepth myDepth;
private String myLockToken;
private String myOwner;
private String myAuthUser;
private Date myTimeOutDate;
public DAVLock(String authUser, DAVDepth depth, boolean isLockNull, String lockToken, String owner, DAVLockRecType recType,
DAVLockScope scope, DAVLockType type, Date timeOutDate) {
myAuthUser = authUser;
myDepth = depth;
myIsLockNull = isLockNull;
myLockToken = lockToken;
myOwner = owner;
myRecType = recType;
myScope = scope;
myType = type;
myTimeOutDate = timeOutDate;
}
public DAVLockRecType getRecType() {
return myRecType;
}
public DAVLockScope getScope() {
return myScope;
}
public DAVLockType getType() {
return myType;
}
public boolean isLockNull() {
return myIsLockNull;
}
public DAVDepth getDepth() {
return myDepth;
}
public String getLockToken() {
return myLockToken;
}
public String getOwner() {
return myOwner;
}
public String getAuthUser() {
return myAuthUser;
}
public Date getTimeOutDate() {
return myTimeOutDate;
}
}

View File

@@ -0,0 +1,26 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVLockRecType {
public static final DAVLockRecType DIRECT = new DAVLockRecType();
public static final DAVLockRecType INDIRECT = new DAVLockRecType();
public static final DAVLockRecType INDIRECT_PARTIAL = new DAVLockRecType();
private DAVLockRecType() {
}
}

View File

@@ -0,0 +1,26 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVLockScope {
public static final DAVLockScope EXCLUSIVE = new DAVLockScope();
public static final DAVLockScope UNKNOWN = new DAVLockScope();
public static final DAVLockScope SHARED = new DAVLockScope();
private DAVLockScope() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVLockType {
public static final DAVLockType UNKNOWN = new DAVLockType();
public static final DAVLockType WRITE = new DAVLockType();
private DAVLockType() {
}
}

View File

@@ -0,0 +1,262 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVPathUtil {
private static final String SLASH = "/";
public static String dropLeadingSlash(String uri) {
if (uri == null) {
return "";
}
return uri.startsWith(SLASH) ? uri.substring(SLASH.length()) : uri;
}
public static String addLeadingSlash(String uri) {
if (uri == null) {
return SLASH;
}
return uri.startsWith(SLASH) ? uri : SLASH + uri;
}
public static String dropTraillingSlash(String uri) {
if (uri == null) {
return "";
}
return uri.endsWith(SLASH) ? uri.substring(0, uri.length() - SLASH.length()) : uri;
}
public static String addTrailingSlash(String uri) {
if (uri == null) {
return SLASH;
}
return uri.endsWith(SLASH) ? uri : uri + SLASH;
}
public static String head(String uri) {
uri = dropLeadingSlash(uri);
int slashIndex = uri.indexOf(SLASH);
if (slashIndex == -1) {
return uri;
}
return uri.substring(0, slashIndex);
}
public static String removeHead(String uri, boolean doStandardize) {
uri = dropLeadingSlash(uri);
int headLength = head(uri).length();
return doStandardize ? standardize(uri.substring(headLength)) : uri.substring(headLength);
}
public static String tail(String uri) {
uri = dropTraillingSlash(uri);
int lastSlashIndex = uri.lastIndexOf(SLASH);
if (lastSlashIndex == -1) {
return uri;
}
return uri.substring(lastSlashIndex);
}
public static String removeTail(String uri, boolean doStandardize) {
uri = dropTraillingSlash(uri);
int tailLength = tail(uri).length();
return doStandardize ? standardize(uri.substring(0, uri.length() - tailLength)) : uri.substring(0, uri.length() - tailLength);
}
public static String append(String parent, String child) {
StringBuffer uriBuffer = new StringBuffer();
uriBuffer.append(standardize(parent));
uriBuffer.append(standardize(child));
return uriBuffer.toString();
}
public static String standardize(String uri) {
if (uri == null) {
return SLASH;
}
return addLeadingSlash(dropTraillingSlash(uri));
}
public static String normalize(String uri) {
return "".equals(uri) ? SLASH : uri;
}
public static void testCanonical(String path) throws DAVException {
if (path != null && !path.equals(SVNPathUtil.canonicalizePath(path))) {
throw new DAVException("Path ''{0}'' is not canonicalized;\nthere is a problem with the client.", new Object[] { path },
HttpServletResponse.SC_BAD_REQUEST, null, SVNLogType.NETWORK, Level.FINE, null, DAVXMLUtil.SVN_DAV_ERROR_TAG,
DAVElement.SVN_DAV_ERROR_NAMESPACE, 0, null);
}
}
public static String buildURI(String context, DAVResourceKind davResourceKind, long revision, String path, boolean addHref) {
StringBuffer resultURI = new StringBuffer();
path = path == null ? "" : SVNEncodingUtil.uriEncode(path);
context = context == null ? "" : context;
if (addHref) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA,
null, resultURI);
}
resultURI.append(context);
resultURI.append(SLASH);
if (davResourceKind == DAVResourceKind.PUBLIC) {
resultURI.append(dropLeadingSlash(path));
} else {
resultURI.append(DAVResourceURI.SPECIAL_URI).append(SLASH);
if (davResourceKind == DAVResourceKind.ACT_COLLECTION) {
resultURI.append(davResourceKind.toString());
resultURI.append(SLASH);
} else if (davResourceKind == DAVResourceKind.BASELINE) {
resultURI.append(davResourceKind.toString());
resultURI.append(SLASH);
resultURI.append(String.valueOf(revision));
} else if (davResourceKind == DAVResourceKind.BASELINE_COLL) {
resultURI.append(davResourceKind.toString());
resultURI.append(SLASH);
resultURI.append(String.valueOf(revision));
resultURI.append(addLeadingSlash(path));
} else if (davResourceKind == DAVResourceKind.VERSION) {
resultURI.append(davResourceKind.toString());
resultURI.append(SLASH);
resultURI.append(String.valueOf(revision));
resultURI.append(addLeadingSlash(path));
} else if (davResourceKind == DAVResourceKind.VCC) {
resultURI.append(davResourceKind.toString());
resultURI.append(SLASH);
resultURI.append(DAVResourceURI.DEDAULT_VCC_NAME);
}
}
if (addHref) {
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), resultURI, false);
}
return resultURI.toString();
}
public static File getActivityPath(File activitiesDB, String activityID) {
String safeActivityID = SVNFileUtil.computeChecksum(activityID);
File finalActivityFile = new File(activitiesDB, safeActivityID);
return finalActivityFile;
}
public static DAVURIInfo simpleParseURI(String uri, DAVResource relative) throws SVNException {
URI parsedURI = null;
try {
parsedURI = new URI(uri);
} catch (URISyntaxException urise) {
throwMalformedURIErrorException();
}
String path = parsedURI.getPath();
if ("".equals(path)) {
path = "/";
}
String reposRoot = relative.getResourceURI().getContext();
if (!path.equals(reposRoot) && (!path.startsWith(reposRoot) || path.charAt(reposRoot.length()) != '/')) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.APMOD_MALFORMED_URI, "Unusable URI: it does not refer to this repository");
SVNErrorManager.error(err, SVNLogType.NETWORK);
}
long revision = SVNRepository.INVALID_REVISION;
path = path.substring(reposRoot.length());
if ("".equals(path) || "/".equals(path)) {
return new DAVURIInfo(null, "/", revision);
}
path = path.substring(1);
String specialURI = DAVResourceURI.SPECIAL_URI;
if (!path.equals(specialURI) && (!path.startsWith(specialURI) || path.charAt(specialURI.length()) != '/')) {
path = !path.startsWith("/") ? "/" + path : path;
return new DAVURIInfo(null, path, revision);
}
path = path.substring(specialURI.length());
if ("".equals(path) || "/".equals(path)) {
throwUnhandledFormException();
}
int slashInd = path.indexOf('/', 1);
if (slashInd == -1 || slashInd == path.length() -1) {
throwUnhandledFormException();
}
String segment = path.substring(0, slashInd + 1);
String activityID = null;
String reposPath = null;
if ("/act/".equals(segment)) {
activityID = path.substring(slashInd + 1);
} else if ("/ver/".equals(segment)) {
int nextSlashInd = path.indexOf('/', slashInd + 1);
if (nextSlashInd == -1) {
try {
revision = Long.parseLong(path.substring(slashInd + 1));
} catch (NumberFormatException nfe) {
throwMalformedURIErrorException();
}
reposPath = "/";
} else {
segment = path.substring(slashInd + 1, nextSlashInd);
try {
revision = Long.parseLong(segment);
} catch (NumberFormatException nfe) {
throwMalformedURIErrorException();
}
reposPath = SVNEncodingUtil.uriDecode(path.substring(nextSlashInd));
}
if (!SVNRevision.isValidRevisionNumber(revision)) {
throwMalformedURIErrorException();
}
} else {
throwUnhandledFormException();
}
return new DAVURIInfo(activityID, reposPath, revision);
}
private static void throwMalformedURIErrorException() throws SVNException {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.APMOD_MALFORMED_URI, "The specified URI could not be parsed");
SVNErrorManager.error(err, SVNLogType.NETWORK);
}
private static void throwUnhandledFormException() throws SVNException {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNSUPPORTED_FEATURE, "Unsupported URI form");
SVNErrorManager.error(err, SVNLogType.NETWORK);
}
}

View File

@@ -0,0 +1,49 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import org.tmatesoft.svn.core.io.SVNRepository;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVPrivateResourceHelper extends DAVResourceHelper {
protected void prepare(DAVResource resource) throws DAVException {
}
protected DAVResource getParentResource(DAVResource resource) throws DAVException {
DAVResourceHelper.throwIllegalGetParentResourceError(resource);
return null;
}
public static DAVResource createPrivateResource(DAVResource resource, DAVResourceKind resourceKind) {
DAVResource privateResource = new DAVResource();
resource.copyTo(privateResource);
DAVResourceURI resourceURI = privateResource.getResourceURI();
resourceURI.setKind(resourceKind);
resourceURI.setType(DAVResourceType.PRIVATE);
String path = "/" + DAVResourceURI.SPECIAL_URI + "/" + resourceKind.toString();
resourceURI.setURI(path);
resourceURI.setPath(null);
privateResource.setCollection(true);
privateResource.setExists(true);
privateResource.setRevision(SVNRepository.INVALID_REVISION);
return privateResource;
}
}

View File

@@ -0,0 +1,80 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVRegularResourceHelper extends DAVResourceHelper {
protected void prepare(DAVResource resource) throws DAVException {
if (!SVNRevision.isValidRevisionNumber(resource.getRevision())) {
try {
resource.setRevision(resource.getLatestRevision());
} catch (SVNException e) {
throw DAVException.convertError(e.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not determine the proper revision to access", null);
}
}
FSRoot root = resource.getRoot();
FSFS fsfs = resource.getFSFS();
if (root == null) {
try {
root = fsfs.createRevisionRoot(resource.getRevision());
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not open the root of the repository", null);
}
resource.setRoot(root);
}
SVNNodeKind kind = DAVServletUtil.checkPath(root, resource.getResourceURI().getPath());
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "resource path is " + resource.getResourceURI().getPath());
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "resource kind is " + kind);
resource.setExists(kind != SVNNodeKind.NONE);
resource.setCollection(kind == SVNNodeKind.DIR);
}
protected DAVResource getParentResource(DAVResource resource) throws DAVException {
DAVResource parentResource = new DAVResource();
resource.copyTo(parentResource);
DAVResourceURI parentResourceURI = parentResource.getResourceURI();
String uri = parentResourceURI.getURI();
String path = parentResourceURI.getPath();
parentResourceURI.setURI(SVNPathUtil.removeTail(uri));
parentResourceURI.setPath(SVNPathUtil.removeTail(path));
parentResource.setExists(true);
parentResource.setCollection(true);
parentResource.setVersioned(true);
return parentResource;
}
}

View File

@@ -0,0 +1,309 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.File;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVHandlerFactory;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVRepositoryManager {
private static final String FILE_PROTOCOL_LINE = "file://";
private static final String DESTINATION_HEADER = "Destination";
private static final String DEFAULT_ACTIVITY_DB = "dav/activities.d";
private DAVConfig myDAVConfig;
private String myResourceRepositoryRoot;
private String myResourceContext;
private String myResourcePathInfo;
private Principal myUserPrincipal;
private File myRepositoryRootDir;
public DAVRepositoryManager(DAVConfig config, HttpServletRequest request) throws SVNException {
if (config == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE), SVNLogType.NETWORK);
}
myDAVConfig = config;
myResourceRepositoryRoot = getRepositoryRoot(request.getPathInfo());
myResourceContext = getResourceContext(request);
myUserPrincipal = request.getUserPrincipal();
myRepositoryRootDir = getRepositoryRootDir(request.getPathInfo());
myResourcePathInfo = getResourcePathInfo(request);
if (config.isUsingPBA()) {
String path = null;
if (!DAVHandlerFactory.METHOD_MERGE.equals(request.getMethod())) {
DAVResourceURI tmp = new DAVResourceURI(null, myResourcePathInfo, null, false);
path = DAVPathUtil.standardize(tmp.getPath());
}
boolean checkDestinationPath = false;
String destinationPath = null;
if (DAVHandlerFactory.METHOD_MOVE.equals(request.getMethod()) || DAVHandlerFactory.METHOD_COPY.equals(request.getMethod())) {
String destinationURL = request.getHeader(DESTINATION_HEADER);
if (destinationURL == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Destination path missing"), SVNLogType.NETWORK);
}
destinationPath = DAVPathUtil.standardize(getRepositoryRelativePath(SVNURL.parseURIEncoded(destinationURL)));
checkDestinationPath = true;
}
String repository = getResourceRepositoryName(request.getPathInfo());
String user = request.getRemoteUser();
int access = getRequestedAccess(request.getMethod());
checkAccess(repository, path, checkDestinationPath, destinationPath, user, access);
}
}
private int getRequestedAccess(String method) {
int access = SVNPathBasedAccess.SVN_ACCESS_NONE;
if (DAVHandlerFactory.METHOD_COPY.equals(method) ||
DAVHandlerFactory.METHOD_MOVE.equals(method) ||
DAVHandlerFactory.METHOD_DELETE.equals(method)) {
access |= SVNPathBasedAccess.SVN_ACCESS_RECURSIVE;
} else if (DAVHandlerFactory.METHOD_OPTIONS.equals(method) ||
DAVHandlerFactory.METHOD_PROPFIND.equals(method) ||
DAVHandlerFactory.METHOD_GET.equals(method) ||
DAVHandlerFactory.METHOD_REPORT.equals(method)) {
access |= SVNPathBasedAccess.SVN_ACCESS_READ;
} else if (DAVHandlerFactory.METHOD_MKCOL.equals(method) ||
DAVHandlerFactory.METHOD_PUT.equals(method) ||
DAVHandlerFactory.METHOD_PROPPATCH.equals(method) ||
DAVHandlerFactory.METHOD_CHECKOUT.equals(method) ||
DAVHandlerFactory.METHOD_MERGE.equals(method) ||
DAVHandlerFactory.METHOD_MKACTIVITY.equals(method) ||
DAVHandlerFactory.METHOD_LOCK.equals(method) ||
DAVHandlerFactory.METHOD_UNLOCK.equals(method)) {
access |= SVNPathBasedAccess.SVN_ACCESS_WRITE;
} else {
access |= SVNPathBasedAccess.SVN_ACCESS_RECURSIVE | SVNPathBasedAccess.SVN_ACCESS_WRITE;
}
return access;
}
private void checkAccess(String repository, String path, boolean checkDestinationPath, String destinationPath, String user, int access) throws SVNException {
if (getDAVConfig().getSVNAccess() == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An error occured while loading configuration file."), SVNLogType.NETWORK);
}
if (!getDAVConfig().isAnonymousAllowed() && user == null) {
SVNErrorManager.authenticationFailed("Anonymous user is not allowed on resource", null);
}
if (path != null || (path == null && (access & SVNPathBasedAccess.SVN_ACCESS_WRITE) != SVNPathBasedAccess.SVN_ACCESS_NONE)) {
if (!getDAVConfig().getSVNAccess().checkAccess(repository, path, user, access)) {
if (user == null) {
SVNErrorManager.authenticationFailed("Forbidden for anonymous", null);
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.NO_AUTH_FILE_PATH), SVNLogType.NETWORK);
}
}
}
if (checkDestinationPath) {
if (path != null) {
if (!getDAVConfig().getSVNAccess().checkAccess(repository, destinationPath, user, access)) {
if (user == null) {
SVNErrorManager.authenticationFailed("Forbidden for anonymous", null);
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.NO_AUTH_FILE_PATH), SVNLogType.NETWORK);
}
}
}
}
}
public DAVConfig getDAVConfig() {
return myDAVConfig;
}
public String getResourceRepositoryRoot() {
return myResourceRepositoryRoot;
}
public String getResourceContext() {
return myResourceContext;
}
public String getResourcePathInfo() {
return myResourcePathInfo;
}
public SVNURL convertHttpToFile(SVNURL url) throws SVNException {
String uri = DAVPathUtil.addLeadingSlash(url.getURIEncodedPath());
if (!uri.startsWith(getResourceContext())) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Invalid URL ''{0}'' requested", url.toString()), SVNLogType.NETWORK);
}
return SVNURL.parseURIEncoded(getResourceRepositoryRoot() + getRepositoryRelativePath(url));
}
public String getRepositoryRelativePath(SVNURL url) throws SVNException {
String uri = getURI(url);
DAVResourceURI resourceURI = new DAVResourceURI(null, uri, null, false);
return resourceURI.getPath();
}
public String getURI(SVNURL url) throws SVNException {
String uri = DAVPathUtil.addLeadingSlash(url.getURIEncodedPath());
if (uri.startsWith(getResourceContext())) {
uri = uri.substring(getResourceContext().length());
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Invalid URL ''{0}'' requested", url.toString()),
SVNLogType.NETWORK);
}
return uri;
}
public DAVResource getRequestedDAVResource(boolean isSVNClient, String deltaBase, String pathInfo, long version, String clientOptions,
String baseChecksum, String resultChecksum, String label, boolean useCheckedIn, List lockTokens, Map capabilities) throws SVNException {
pathInfo = pathInfo == null ? getResourcePathInfo() : pathInfo;
DAVResourceURI resourceURI = new DAVResourceURI(getResourceContext(), pathInfo, label, useCheckedIn);
DAVConfig config = getDAVConfig();
String fsParentPath = config.getRepositoryParentPath();
String xsltURI = config.getXSLTIndex();
String reposName = config.getRepositoryName();
String uri = resourceURI.getURI();
if (fsParentPath != null && getDAVConfig().isListParentPath()) {
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() - 1);
}
//TODO: later add code for parent path resource here
}
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "uri type - " + resourceURI.getType() + ", uri kind - " + resourceURI.getKind());
String activitiesDB = config.getActivitiesDBPath();
File activitiesDBDir = null;
if (activitiesDB == null) {
activitiesDBDir = new File(myRepositoryRootDir, DEFAULT_ACTIVITY_DB);
} else {
activitiesDBDir = new File(activitiesDB);
}
String userName = myUserPrincipal != null ? myUserPrincipal.getName() : null;
SVNAuthentication auth = new SVNUserNameAuthentication(userName, false, null, false);
BasicAuthenticationManager authManager = new BasicAuthenticationManager(new SVNAuthentication[] { auth });
SVNRepository resourceRepository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(getResourceRepositoryRoot()));
resourceRepository.setAuthenticationManager(authManager);
DAVResource resource = new DAVResource(resourceRepository, this, resourceURI, isSVNClient, deltaBase, version,
clientOptions, baseChecksum, resultChecksum, userName, activitiesDBDir, lockTokens, capabilities);
return resource;
}
private String getRepositoryRoot(String requestURI) {
StringBuffer repositoryURL = new StringBuffer();
repositoryURL.append(FILE_PROTOCOL_LINE);
if (getDAVConfig().isUsingRepositoryPathDirective()) {
repositoryURL.append(getDAVConfig().getRepositoryPath().startsWith("/") ? "" : "/");
repositoryURL.append(getDAVConfig().getRepositoryPath());
} else {
String reposParentPath = getDAVConfig().getRepositoryParentPath();
if (!reposParentPath.startsWith("/")) {
reposParentPath = "/" + reposParentPath;
}
repositoryURL.append(DAVPathUtil.addTrailingSlash(reposParentPath));
repositoryURL.append(DAVPathUtil.head(requestURI));
}
return repositoryURL.toString();
}
private File getRepositoryRootDir(String requestURI) {
File reposRootDir = null;
if (getDAVConfig().isUsingRepositoryPathDirective()) {
reposRootDir = new File(getDAVConfig().getRepositoryPath());
} else {
reposRootDir = new File(getDAVConfig().getRepositoryParentPath(), DAVPathUtil.head(requestURI));
}
return reposRootDir;
}
private String getResourcePathInfo(HttpServletRequest request) throws SVNException {
String pathInfo = request.getPathInfo();
if (pathInfo == null || "".equals(pathInfo)) {
pathInfo = "/";
}
if (getDAVConfig().isUsingRepositoryPathDirective()) {
return pathInfo;
}
if (pathInfo == null || pathInfo.length() == 0 || "/".equals(pathInfo)) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED), SVNLogType.NETWORK);
//TODO: client tried to access repository parent path, result status code should be FORBIDDEN.
}
return DAVPathUtil.removeHead(pathInfo, true);
}
private String getResourceRepositoryName(String requestURI) {
if (getDAVConfig().isUsingRepositoryPathDirective()) {
return "";
}
return DAVPathUtil.head(requestURI);
}
private String getResourceContext(HttpServletRequest request) {
String requestContext = request.getContextPath();
String pathInfo = request.getPathInfo();
String servletPath = request.getServletPath();
if (getDAVConfig().isUsingRepositoryPathDirective()) {
if (servletPath != null && !"".equals(servletPath)) {
if (servletPath.startsWith("/")) {
servletPath = servletPath.substring(1);
}
requestContext = SVNPathUtil.append(requestContext, servletPath);
}
return SVNEncodingUtil.uriEncode(requestContext);
}
String reposName = DAVPathUtil.head(pathInfo);
if (servletPath != null && !"".equals(servletPath)) {
if (servletPath.startsWith("/")) {
servletPath = servletPath.substring(1);
}
String pathToRepos = SVNPathUtil.append(requestContext, servletPath);
requestContext = SVNPathUtil.append(pathToRepos, reposName);
return SVNEncodingUtil.uriEncode(requestContext);
}
requestContext = DAVPathUtil.append(requestContext, reposName);
return SVNEncodingUtil.uriEncode(requestContext);
}
}

View File

@@ -0,0 +1,631 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.File;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.ISVNDirEntryHandler;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLock;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRepository;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionNode;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVResource {
public static final long INVALID_REVISION = SVNRepository.INVALID_REVISION;
public static final String DEFAULT_COLLECTION_CONTENT_TYPE = "text/html; charset=\"utf-8\"";
public static final String DEFAULT_FILE_CONTENT_TYPE = "text/plain";
private DAVRepositoryManager myRepositoryManager;
private DAVResourceURI myResourceURI;
private FSRepository myRepository;
private long myRevision;
private long myVersion;
private boolean myIsCollection;
private boolean myIsSVNClient;
private boolean myIsAutoCheckedOut;
private String myDeltaBase;
private String myClientOptions;
private String myBaseChecksum;
private String myResultChecksum;
private String myUserName;
private SVNProperties mySVNProperties;
private Collection myDeadProperties;
private Collection myEntries;
private File myActivitiesDB;
private FSFS myFSFS;
private String myTxnName;
private FSRoot myRoot;
private FSTransactionInfo myTxnInfo;
private Map myClientCapabilities;
private Collection myLockTokens;
/**
* DAVResource constructor
*
* @param repository repository resource connect to
* @param context contains requested url requestContext and name of repository if servlet use SVNParentPath directive.
* @param uri special uri for DAV requests can be /path or /SPECIAL_URI/xxx/path
* @param label request's label header
* @param useCheckedIn special case for VCC resource
* @throws SVNException if an error occurs while fetching repository properties.
*/
public DAVResource(SVNRepository repository, DAVRepositoryManager manager, DAVResourceURI resourceURI, boolean isSVNClient, String deltaBase, long version,
String clientOptions, String baseChecksum, String resultChecksum, String userName, File activitiesDB,
Collection lockTokens, Map clientCapabilities) throws DAVException {
myRepositoryManager = manager;
myRepository = (FSRepository) repository;
try {
myRepository.testConnection();//this should create an FSFS object
} catch (SVNException svne) {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.FSFS, svne.getMessage());
SVNErrorMessage err = SVNErrorMessage.create(svne.getErrorMessage().getErrorCode(), "Could not open the requested SVN filesystem");
throw DAVException.convertError(err, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not fetch resource information.", null);
}
myLockTokens = lockTokens;
myClientCapabilities = clientCapabilities;
myFSFS = myRepository.getFSFS();
myResourceURI = resourceURI;
myIsSVNClient = isSVNClient;
myDeltaBase = deltaBase;
myVersion = version;
myClientOptions = clientOptions;
myBaseChecksum = baseChecksum;
myResultChecksum = resultChecksum;
myRevision = resourceURI.getRevision();
myUserName = userName;
myActivitiesDB = activitiesDB;
DAVResourceHelper.prepareResource(this);
}
public DAVResource(DAVRepositoryManager manager, SVNRepository repository, DAVResourceURI resourceURI, long revision, boolean isSVNClient, String deltaBase,
long version, String clientOptions, String baseChecksum, String resultChecksum, String userName, File activitiesDB,
Collection lockTokens, Map clientCapabilities) {
myRepositoryManager = manager;
myResourceURI = resourceURI;
myRepository = (FSRepository) repository;
myFSFS = myRepository.getFSFS();
myRevision = revision;
myIsSVNClient = isSVNClient;
myDeltaBase = deltaBase;
myVersion = version;
myClientOptions = clientOptions;
myBaseChecksum = baseChecksum;
myResultChecksum = resultChecksum;
myUserName = userName;
myActivitiesDB = activitiesDB;
myLockTokens = lockTokens;
myClientCapabilities = clientCapabilities;
}
public DAVResource() {
}
public void setRoot(FSRoot root) {
myRoot = root;
}
public FSRoot getRoot() {
return myRoot;
}
public FSTransactionInfo getTxnInfo() {
return myTxnInfo;
}
public void setTxnInfo(FSTransactionInfo txnInfo) {
myTxnInfo = txnInfo;
}
public DAVResourceURI getResourceURI() {
return myResourceURI;
}
public SVNRepository getRepository() {
return myRepository;
}
public long getRevision() {
return myRevision;
}
public boolean exists() {
return myResourceURI.exists();
}
public boolean isVersioned() {
return myResourceURI.isVersioned();
}
public boolean isWorking() {
return myResourceURI.isWorking();
}
public boolean isBaseLined() {
return myResourceURI.isBaseLined();
}
public DAVResourceType getType() {
return getResourceURI().getType();
}
//TODO: refactor DAVResourceKind later and name
//this method as getPrivateResourceKind()
public DAVResourceKind getKind() {
return getResourceURI().getKind();
}
public String getActivityID() {
return myResourceURI.getActivityID();
}
public boolean lacksETagPotential() {
DAVResourceType type = getResourceURI().getType();
return !exists() || (type != DAVResourceType.REGULAR && type != DAVResourceType.VERSION) ||
(type == DAVResourceType.VERSION && isBaseLined());
}
public boolean canBeActivity() {
return isAutoCheckedOut() || (getType() == DAVResourceType.ACTIVITY && !exists());
}
public boolean isCollection() {
return myIsCollection;
}
public boolean isSVNClient() {
return myIsSVNClient;
}
public DAVAutoVersion getAutoVersion() {
if (getType() == DAVResourceType.VERSION && isBaseLined()) {
return DAVAutoVersion.ALWAYS;
}
DAVConfig config = myRepositoryManager.getDAVConfig();
if (config.isAutoVersioning()) {
if (getType() == DAVResourceType.REGULAR) {
return DAVAutoVersion.ALWAYS;
}
if (getType() == DAVResourceType.WORKING && isAutoCheckedOut()) {
return DAVAutoVersion.ALWAYS;
}
}
return DAVAutoVersion.NEVER;
}
public String getUserName() {
return myUserName;
}
public String getDeltaBase() {
return myDeltaBase;
}
public long getVersion() {
return myVersion;
}
public String getClientOptions() {
return myClientOptions;
}
public String getBaseChecksum() {
return myBaseChecksum;
}
public String getResultChecksum() {
return myResultChecksum;
}
public File getActivitiesDB() {
return myActivitiesDB;
}
public void versionControl(String target) throws DAVException {
if (exists()) {
throw new DAVException("vsn_control called on already-versioned resource.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
if (target != null) {
throw new DAVException("vsn_control called with non-null target.", null, HttpServletResponse.SC_NOT_IMPLEMENTED, null,
SVNLogType.NETWORK, Level.FINE, null, DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE,
SVNErrorCode.UNSUPPORTED_FEATURE.getCode(), null);
}
}
public Iterator getChildren() throws SVNException {
return new Iterator() {
Iterator entriesIterator = getEntries().iterator();
public void remove() {
}
public boolean hasNext() {
return entriesIterator.hasNext();
}
public Object next() {
SVNDirEntry entry = (SVNDirEntry) entriesIterator.next();
String childURI = DAVPathUtil.append(getResourceURI().getURI(), entry.getName());
try {
DAVResourceURI newResourceURI = new DAVResourceURI(getResourceURI().getContext(), childURI, null, false);
return new DAVResource(myRepositoryManager, getRepository(), newResourceURI, getRevision(), isSVNClient(), getDeltaBase(),
getVersion(), getClientOptions(), null, null, getUserName(), getActivitiesDB(), getLockTokens(), getClientCapabilities());
} catch (SVNException e) {
return null;
}
}
};
}
public Map getClientCapabilities() {
return myClientCapabilities;
}
public Collection getLockTokens() {
return myLockTokens;
}
public void setLockTokens(Collection lockTokens) {
if (myLockTokens != null) {
myLockTokens.addAll(lockTokens);
}
myLockTokens = lockTokens;
}
public Collection getEntries() throws SVNException {
if (isCollection() && myEntries == null) {
myEntries = new LinkedList();
getRepository().getDir(getResourceURI().getPath(), getRevision(), null, SVNDirEntry.DIRENT_KIND, myEntries);
}
return myEntries;
}
public long getCreatedRevision() throws SVNException {
String revisionParameter = getProperty(SVNProperty.COMMITTED_REVISION);
try {
return Long.parseLong(revisionParameter);
} catch (NumberFormatException e) {
return getRevision();
}
}
public long getCreatedRevisionUsingFS(String path) throws SVNException {
path = path == null ? getResourceURI().getPath() : path;
FSRevisionNode node = myRoot.getRevisionNode(path);
return node.getCreatedRevision();
}
public Date getLastModified() throws SVNException {
if (lacksETagPotential()) {
return null;
}
return getRevisionDate(getCreatedRevision());
}
public Date getRevisionDate(long revision) throws SVNException {
//TODO: insert here later an authz check
return SVNDate.parseDate(getRevisionProperty(revision, SVNRevisionProperty.DATE));
}
public String getETag() {
if (lacksETagPotential()) {
return null;
}
long createdRevision = -1;
try {
createdRevision = getCreatedRevisionUsingFS(null);
} catch (SVNException svne) {
return null;
}
StringBuffer eTag = new StringBuffer();
eTag.append(isCollection() ? "W/" : "");
eTag.append("\"");
eTag.append(createdRevision);
eTag.append("/");
eTag.append(SVNEncodingUtil.xmlEncodeCDATA(getResourceURI().getPath(), true));
eTag.append("\"");
return eTag.toString();
}
public String getRepositoryUUID(boolean forceConnect) throws SVNException {
return getRepository().getRepositoryUUID(forceConnect);
}
public String getContentType() throws SVNException {
if (getResourceURI().isBaseLined() && getResourceURI().getType() == DAVResourceType.VERSION) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_PROPS_NOT_FOUND, "Failed to determine property"), SVNLogType.NETWORK);
return null;
}
if (getResourceURI().getType() == DAVResourceType.PRIVATE && getResourceURI().getKind() == DAVResourceKind.VCC) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_PROPS_NOT_FOUND, "Failed to determine property"), SVNLogType.NETWORK);
return null;
}
if (isCollection()) {
return DEFAULT_COLLECTION_CONTENT_TYPE;
}
String contentType = getProperty(SVNProperty.MIME_TYPE);
if (contentType != null) {
return contentType;
}
return DEFAULT_FILE_CONTENT_TYPE;
}
public long getLatestRevision() throws SVNException {
return getRepository().getLatestRevision();
}
//TODO: remove this method later, use getContentLength(String path) instead
/**
* @deprecated
*/
public long getContentLength() throws SVNException {
SVNDirEntry entry = getRepository().getDir(getResourceURI().getPath(), getRevision(), false, null);
return entry.getSize();
}
public long getContentLength(String path) throws SVNException {
path = path == null ? getResourceURI().getPath() : path;
FSRevisionNode node = myRoot.getRevisionNode(path);
return node.getFileLength();
}
public SVNLock[] getLocks() throws SVNException {
if (getResourceURI().getPath() == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "get-locks-report run on resource which doesn't represent a path within a repository."), SVNLogType.NETWORK);
}
return getRepository().getLocks(getResourceURI().getPath());
}
public SVNLock getLock() throws SVNException {
return getRepository().getLock(getResourceURI().getPath());
}
public void unlock(String token, boolean force) throws SVNException {
Map pathsToTokens = new HashMap();
pathsToTokens.put(getResourceURI().getPath(), token);
getRepository().unlock(pathsToTokens, force, null);
}
public String getAuthor(long revision) throws SVNException {
return getRevisionProperty(revision, SVNRevisionProperty.AUTHOR);
}
/**
* @deprecated use getMD5Checksum() instead
*/
public String getMD5Checksum() throws SVNException {
return getProperty(SVNProperty.CHECKSUM);
}
public String getMD5Checksum(String path) throws SVNException {
path = path == null ? getResourceURI().getPath() : path;
FSRevisionNode node = myRoot.getRevisionNode(path);
return node.getFileMD5Checksum();
}
public String getLog(long revision) throws SVNException {
return getRevisionProperty(revision, SVNRevisionProperty.LOG);
}
//TODO: replace later with getProperty(path, propName)
/**
* @deprecated
*/
public String getProperty(String propertyName) throws SVNException {
return getSVNProperties().getStringValue(propertyName);
}
public SVNPropertyValue getProperty(String path, String propertyName) throws SVNException {
return getSVNProperties(path).getSVNPropertyValue(propertyName);
}
public String getRevisionProperty(long revision, String propertyName) throws SVNException {
SVNPropertyValue value = getRepository().getRevisionPropertyValue(revision, propertyName);
return value == null ? null : value.getString();
}
public void writeTo(OutputStream out) throws SVNException {
if (isCollection()) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED), SVNLogType.NETWORK);
}
getRepository().getFile(getResourceURI().getPath(), getRevision(), null, out);
}
public boolean isAutoCheckedOut() {
return myIsAutoCheckedOut;
}
public void setIsAutoCkeckedOut(boolean isAutoCheckedOut) {
myIsAutoCheckedOut = isAutoCheckedOut;
}
public String getTxnName() {
return myTxnName;
}
public void setExists(boolean exists) {
myResourceURI.setExists(exists);
}
public void setVersioned(boolean isVersioned) {
myResourceURI.setVersioned(isVersioned);
}
public void setWorking(boolean isWorking) {
myResourceURI.setWorking(isWorking);
}
public void setBaseLined(boolean isBaseLined) {
myResourceURI.setBaseLined(isBaseLined);
}
public void setCollection(boolean isCollection) {
myIsCollection = isCollection;
}
public void setTxnName(String txnName) {
myTxnName = txnName;
}
public void setRevision(long revision) {
myRevision = revision;
myResourceURI.setRevision(revision);
}
public void setResourceURI(DAVResourceURI resourceURI) {
myResourceURI = resourceURI;
}
public boolean equals(Object o) {
if (o == null || o.getClass() != this.getClass()) {
return false;
}
if (o == this) {
return true;
}
DAVResource otherResource = (DAVResource) o;
if (!isOurResource(otherResource)) {
return false;
}
String myRequestURI = myResourceURI.getRequestURI();
String otherRequestURI = otherResource.getResourceURI().getRequestURI();
return myRequestURI.equals(otherRequestURI);
}
public DAVResource dup() {
DAVResource copy = new DAVResource();
copyTo(copy);
return copy;
}
public FSFS getFSFS() {
return myFSFS;
}
public DAVRepositoryManager getRepositoryManager() {
return myRepositoryManager;
}
public boolean isParentResource(DAVResource resource) {
if (!isOurResource(resource)) {
return false;
}
String thisURIPath = myResourceURI.getURI();
String otherURIPath = resource.getResourceURI().getURI();
return otherURIPath.length() > thisURIPath.length() && otherURIPath.startsWith(thisURIPath) &&
otherURIPath.charAt(thisURIPath.length()) == '/';
}
public SVNProperties getSVNProperties(String path) throws SVNException {
path = path == null ? getResourceURI().getPath() : path;
if (mySVNProperties == null) {
mySVNProperties = myFSFS.getProperties(myRoot.getRevisionNode(path));
}
return mySVNProperties;
}
private boolean isOurResource(DAVResource resource) {
File reposRoot1 = myFSFS.getDBRoot();
File reposRoot2 = resource.myFSFS.getDBRoot();
if (!reposRoot1.equals(reposRoot2)) {
return false;
}
return true;
}
//TODO: replace occurances of getSVNProperties() with getSVNProperties(path)
/**
* @deprecated
*/
public SVNProperties getSVNProperties() throws SVNException {
if (mySVNProperties == null) {
mySVNProperties = new SVNProperties();
if (getResourceURI().getType() == DAVResourceType.REGULAR) {
if (isCollection()) {
getRepository().getDir(getResourceURI().getPath(), getRevision(), mySVNProperties, (ISVNDirEntryHandler) null);
} else {
getRepository().getFile(getResourceURI().getPath(), getRevision(), mySVNProperties, null);
}
}
}
return mySVNProperties;
}
protected void copyTo(DAVResource copy) {
copy.myRepositoryManager = myRepositoryManager;
copy.myResourceURI = myResourceURI.dup();
copy.myRepository = myRepository;
copy.myRevision = myRevision;
copy.myIsCollection = myIsCollection;
copy.myIsSVNClient = myIsCollection;
copy.myIsAutoCheckedOut = myIsAutoCheckedOut;
copy.myDeltaBase = myDeltaBase;
copy.myVersion = myVersion;
copy.myClientOptions = myClientOptions;
copy.myBaseChecksum = myBaseChecksum;
copy.myResultChecksum = myResultChecksum;
copy.myUserName = myUserName;
copy.mySVNProperties = mySVNProperties;
copy.myDeadProperties = myDeadProperties;
copy.myEntries = myEntries;
copy.myActivitiesDB = myActivitiesDB;
copy.myFSFS = myFSFS;
copy.myTxnName = myTxnName;
copy.myRoot = myRoot;
copy.myTxnInfo = myTxnInfo;
copy.myClientCapabilities = myClientCapabilities;
copy.myLockTokens = myLockTokens;
}
}

View File

@@ -0,0 +1,134 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVLockInfoProvider;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public abstract class DAVResourceHelper {
private static final Map ourResourceHelpers = new HashMap();
static {
registerHelper(DAVResourceType.WORKING, new DAVWorkingResourceHelper());
registerHelper(DAVResourceType.REGULAR, new DAVRegularResourceHelper());
registerHelper(DAVResourceType.ACTIVITY, new DAVActivityResourceHelper());
registerHelper(DAVResourceType.HISTORY, new DAVHistoryResourceHelper());
registerHelper(DAVResourceType.PRIVATE, new DAVPrivateResourceHelper());
registerHelper(DAVResourceType.VERSION, new DAVVersionResourceHelper());
}
protected abstract void prepare(DAVResource resource) throws DAVException;
protected abstract DAVResource getParentResource(DAVResource resource) throws DAVException;
public static void prepareResource(DAVResource resource) throws DAVException {
DAVResourceURI resourceURI = resource.getResourceURI();
DAVResourceType resourceType = resourceURI.getType();
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "resource type is " + resourceType.toString());
DAVResourceHelper helperImpl = getHelper(resourceType);
helperImpl.prepare(resource);
}
public static DAVResource createParentResource(DAVResource resource) throws DAVException {
DAVResourceURI resourceURI = resource.getResourceURI();
DAVResourceType resourceType = resourceURI.getType();
DAVResourceHelper helperImpl = getHelper(resourceType);
return helperImpl.getParentResource(resource);
}
public static DAVResource getDirectResource(DAVLockInfoProvider lockProvider, String lockToken, DAVResource resource) throws DAVException {
while (resource != null) {
DAVLock lock = lockProvider.findLock(resource, lockToken);
if (lock == null) {
throw new DAVException("The specified locktoken does not correspond to an existing lock on this resource.",
HttpServletResponse.SC_BAD_REQUEST, 0);
}
if (lock.getRecType() == DAVLockRecType.DIRECT) {
return resource;
}
resource = createParentResource(resource);
}
throw new DAVException("The lock database is corrupt. A direct lock could not be found for the corresponding indirect lock on this resource.",
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
public static void throwIllegalGetParentResourceError(DAVResource resource) throws DAVException {
DAVResourceURI uri = resource.getResourceURI();
throw new DAVException("getParentResource() was called for {0} (type {1})", new Object[] { uri.getRequestURI(),
uri.getType() }, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
public static void convertWorkingToRegular(DAVResource resource) throws DAVException {
DAVResourceURI uri = resource.getResourceURI();
uri.setType(DAVResourceType.REGULAR);
resource.setWorking(false);
String path = null;
FSFS fsfs = resource.getFSFS();
if (!SVNRevision.isValidRevisionNumber(resource.getRevision())) {
long rev = SVNRepository.INVALID_REVISION;
try {
rev = resource.getLatestRevision();
} catch (SVNException e) {
throw DAVException.convertError(e.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not determine youngest rev.", null);
}
resource.setRevision(rev);
path = uri.getPath();
} else {
path = DAVPathUtil.buildURI(uri.getContext(), DAVResourceKind.BASELINE_COLL, resource.getRevision(), uri.getPath(), false);
}
path = SVNEncodingUtil.uriEncode(path);
uri.setURI(path);
try {
resource.setRoot(fsfs.createRevisionRoot(resource.getRevision()));
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not open revision root.", null);
}
}
private static DAVResourceHelper getHelper(DAVResourceType resourceType) throws DAVException {
DAVResourceHelper helperImpl = (DAVResourceHelper) ourResourceHelpers.get(resourceType);
if (helperImpl == null) {
throw new DAVException("DESIGN FAILURE: unknown resource type", null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null,
SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
return helperImpl;
}
protected synchronized static void registerHelper(DAVResourceType resourceType, DAVResourceHelper factoryImpl) {
ourResourceHelpers.put(resourceType, factoryImpl);
}
}

View File

@@ -0,0 +1,63 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVResourceKind {
public static final DAVResourceKind ACT_COLLECTION = new DAVResourceKind("act");
public static final DAVResourceKind BASELINE = new DAVResourceKind("bln");
public static final DAVResourceKind BASELINE_COLL = new DAVResourceKind("bc");
public static final DAVResourceKind HISTORY = new DAVResourceKind("his");
public static final DAVResourceKind WORKING = new DAVResourceKind("wrk");
public static final DAVResourceKind PUBLIC = new DAVResourceKind("");
public static final DAVResourceKind VERSION = new DAVResourceKind("ver");
public static final DAVResourceKind VCC = new DAVResourceKind("vcc");
public static final DAVResourceKind WRK_BASELINE = new DAVResourceKind("wbl");
public static final DAVResourceKind ROOT_COLLECTION = new DAVResourceKind("rc");
public static final DAVResourceKind UNKNOWN = new DAVResourceKind(null);
private String myKind;
private DAVResourceKind(String kind) {
myKind = kind;
}
public String toString() {
return myKind;
}
public static DAVResourceKind parseKind(String kind) {
if ("act".equals(kind)) {
return ACT_COLLECTION;
} else if ("bln".equals(kind)) {
return BASELINE;
} else if ("bc".equals(kind)) {
return BASELINE_COLL;
} else if ("".equals(kind)) {
return PUBLIC;
} else if ("ver".equals(kind)) {
return VERSION;
} else if ("his".equals(kind)) {
return HISTORY;
} else if ("wrk".equals(kind)) {
return WORKING;
} else if ("wbl".equals(kind)) {
return WRK_BASELINE;
} else if ("vcc".equals(kind)) {
return VCC;
}
return UNKNOWN;
}
}

View File

@@ -0,0 +1,35 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVResourceState {
public final static DAVResourceState NULL = new DAVResourceState(11);
public final static DAVResourceState LOCK_NULL = new DAVResourceState(10);
public final static DAVResourceState EXISTS = new DAVResourceState(12);
public final static DAVResourceState ERROR = new DAVResourceState(13);
private int myID;
private DAVResourceState(int id) {
myID = id;
}
public int getID() {
return myID;
}
}

View File

@@ -0,0 +1,36 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVResourceType {
public static final DAVResourceType REGULAR = new DAVResourceType("regular");
public static final DAVResourceType WORKING = new DAVResourceType("working");
public static final DAVResourceType VERSION = new DAVResourceType("version");
public static final DAVResourceType PRIVATE = new DAVResourceType("private");
public static final DAVResourceType ACTIVITY = new DAVResourceType("activity");
public static final DAVResourceType HISTORY = new DAVResourceType("history");
public static final DAVResourceType WORKSPACE = new DAVResourceType("workspace");
private String myName;
private DAVResourceType(String name) {
myName = name;
}
public String toString() {
return myName;
}
}

View File

@@ -0,0 +1,349 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVResourceURI {
public static final String SPECIAL_URI = "!svn";
public static final String DEDAULT_VCC_NAME = "default";
private String myURI;
private String myContext;
private DAVResourceType myType;
private DAVResourceKind myKind;
private long myRevision;
private String myPath;
private String myActivityID;
private boolean myIsExists = false;
private boolean myIsVersioned = false;
private boolean myIsBaseLined = false;
private boolean myIsWorking = false;
public DAVResourceURI(String context, String uri, String label, boolean useCheckedIn) throws SVNException {
StringBuffer logBuffer = new StringBuffer();
logBuffer.append('\n');
logBuffer.append("uri: " + uri);
logBuffer.append('\n');
logBuffer.append("label: " + label);
logBuffer.append('\n');
logBuffer.append("context: " + context);
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, logBuffer.toString());
myURI = uri == null ? "" : uri;
myContext = context;
myRevision = DAVResource.INVALID_REVISION;
parseURI(label, useCheckedIn);
logBuffer.delete(0, logBuffer.length());
logBuffer.append('\n');
logBuffer.append("DAVResourceURI.getRequestURI(): " + getRequestURI());
logBuffer.append('\n');
logBuffer.append("DAVResourceURI.getURI(): " + getURI());
logBuffer.append('\n');
logBuffer.append("DAVResourceURI.getPath(): " + getPath());
logBuffer.append('\n');
logBuffer.append("DAVResourceURI.getContext(): " + getContext());
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, logBuffer.toString());
}
public DAVResourceURI(String context, String uri, String path, long revision, DAVResourceKind kind, DAVResourceType type, String activityID,
boolean exists, boolean isVersioned, boolean isBaseLined, boolean isWorking) {
myContext = context;
myURI = uri;
myPath = path;
myActivityID = activityID;
myRevision = revision;
myType = type;
myKind = kind;
myIsExists = exists;
myIsVersioned = isVersioned;
myIsBaseLined = isBaseLined;
myIsWorking = isWorking;
}
public DAVResourceURI() {
}
public DAVResourceURI dup() {
return new DAVResourceURI(myContext, myURI, myPath, myRevision, myKind, myType, myActivityID, myIsExists, myIsVersioned, myIsBaseLined,
myIsWorking);
}
public String getRequestURI() {
return SVNPathUtil.append(getContext(), getURI());
}
public String getContext() {
return myContext;
}
public String getURI() {
return myURI;
}
public void setURI(String uri) {
myURI = uri;
}
public DAVResourceType getType() {
return myType;
}
public DAVResourceKind getKind() {
return myKind;
}
public long getRevision() {
return myRevision;
}
public String getPath() {
return myPath;
}
public String getActivityID() {
return myActivityID;
}
public boolean exists() {
return myIsExists;
}
public boolean isVersioned() {
return myIsVersioned;
}
public boolean isBaseLined() {
return myIsBaseLined;
}
public boolean isWorking() {
return myIsWorking;
}
public void setExists(boolean isExist) {
myIsExists = isExist;
}
public void setPath(String path) {
myPath = DAVPathUtil.standardize(path);
}
public void setVersioned(boolean isVersioned) {
myIsVersioned = isVersioned;
}
public void setKind(DAVResourceKind kind) {
myKind = kind;
}
public void setType(DAVResourceType type) {
myType = type;
}
public void setRevision(long revisionNumber) {
myRevision = revisionNumber;
}
public void setWorking(boolean isWorking) {
myIsWorking = isWorking;
}
public void setActivityID(String activityID) {
myActivityID = activityID;
}
public void setBaseLined(boolean isBaseLined) {
myIsBaseLined = isBaseLined;
}
private void parseURI(String label, boolean useCheckedIn) throws SVNException {
if (!SPECIAL_URI.equals(DAVPathUtil.head(getURI()))) {
setKind(DAVResourceKind.PUBLIC);
setType(DAVResourceType.REGULAR);
setPath(getURI());
setVersioned(true);
} else {
String specialPart = DAVPathUtil.removeHead(getURI(), false);
if (specialPart.length() == 0) {
// root/!svn
setType(DAVResourceType.PRIVATE);
setKind(DAVResourceKind.ROOT_COLLECTION);
} else {
specialPart = DAVPathUtil.dropLeadingSlash(specialPart);
if (!specialPart.endsWith("/") && SVNPathUtil.getSegmentsCount(specialPart) == 1) {
// root/!svn/XXX
setType(DAVResourceType.PRIVATE);
} else {
DAVResourceKind kind = DAVResourceKind.parseKind(DAVPathUtil.head(specialPart));
if (kind != DAVResourceKind.UNKNOWN) {
setKind(kind);
String parameter = DAVPathUtil.removeHead(specialPart, false);
parameter = DAVPathUtil.dropLeadingSlash(parameter);
if (kind == DAVResourceKind.VCC) {
parseVCC(parameter, label, useCheckedIn);
} else if (kind == DAVResourceKind.VERSION) {
parseVersion(parameter);
} else if (kind == DAVResourceKind.BASELINE) {
parseBaseline(parameter);
} else if (kind == DAVResourceKind.BASELINE_COLL) {
parseBaselineCollection(parameter);
} else if (kind == DAVResourceKind.ACT_COLLECTION) {
parseActivity(parameter);
} else if (kind == DAVResourceKind.HISTORY) {
parseHistory(parameter);
} else if (kind == DAVResourceKind.WRK_BASELINE) {
parseWorkingBaseline(parameter);
} else if (kind == DAVResourceKind.WORKING) {
parseWorking(parameter);
}
}
}
}
}
}
private void parseWorking(String parameter) {
setType(DAVResourceType.WORKING);
setVersioned(true);
setWorking(true);
if (SVNPathUtil.getSegmentsCount(parameter) == 1) {
setActivityID(parameter);
setPath("/");
} else {
setActivityID(DAVPathUtil.head(parameter));
setPath(DAVPathUtil.removeHead(parameter, false));
}
}
private void parseWorkingBaseline(String parameter) throws SVNException {
setType(DAVResourceType.WORKING);
setWorking(true);
setVersioned(true);
setBaseLined(true);
if (SVNPathUtil.getSegmentsCount(parameter) == 1) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "Invalid URI ''{0}''", getRequestURI()), SVNLogType.NETWORK);
}
setActivityID(DAVPathUtil.head(parameter));
try {
String revisionParameter = DAVPathUtil.removeHead(parameter, false);
long revision = Long.parseLong(DAVPathUtil.dropLeadingSlash(revisionParameter));
setRevision(revision);
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, e), e, SVNLogType.NETWORK);
}
}
private void parseHistory(String parameter) {
setType(DAVResourceType.HISTORY);
setPath(parameter);
}
private void parseActivity(String parameter) {
setType(DAVResourceType.ACTIVITY);
setActivityID(parameter);
}
private void parseBaselineCollection(String parameter) throws SVNException {
long revision = DAVResource.INVALID_REVISION;
String parameterPath;
if (SVNPathUtil.getSegmentsCount(parameter) == 1) {
parameterPath = "/";
try {
revision = Long.parseLong(parameter);
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, e.getMessage()), e, SVNLogType.NETWORK);
}
} else {
try {
revision = Long.parseLong(DAVPathUtil.head(parameter));
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, e.getMessage()), e, SVNLogType.NETWORK);
}
parameterPath = DAVPathUtil.removeHead(parameter, false);
}
setType(DAVResourceType.REGULAR);
setVersioned(true);
setRevision(revision);
setPath(parameterPath);
}
private void parseBaseline(String parameter) throws SVNException {
try {
setRevision(Long.parseLong(parameter));
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, e.getMessage()), e, SVNLogType.NETWORK);
}
setVersioned(true);
setBaseLined(true);
setType(DAVResourceType.VERSION);
}
private void parseVersion(String parameter) throws SVNException {
setVersioned(true);
setType(DAVResourceType.VERSION);
if (SVNPathUtil.getSegmentsCount(parameter) == 1) {
try {
setRevision(Long.parseLong(parameter));
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "Invalid URI ''{0}''", e.getMessage()), e, SVNLogType.NETWORK);
}
setPath("/");
} else {
try {
setRevision(Long.parseLong(DAVPathUtil.head(parameter)));
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, e.getMessage()), e, SVNLogType.NETWORK);
}
setPath(DAVPathUtil.removeHead(parameter, false));
}
}
private void parseVCC(String parameter, String label, boolean useCheckedIn) throws SVNException {
if (!DEDAULT_VCC_NAME.equals(parameter)) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Invalid VCC name ''{0}''", parameter), SVNLogType.NETWORK);
}
if (label == null && !useCheckedIn) {
setType(DAVResourceType.PRIVATE);
setExists(true);
setVersioned(true);
setBaseLined(true);
} else {
long revision = DAVResource.INVALID_REVISION;
if (label != null) {
try {
revision = Long.parseLong(label);
} catch (NumberFormatException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "Invalid label header ''{0}''", label), SVNLogType.NETWORK);
}
}
setType(DAVResourceType.VERSION);
setRevision(revision);
setVersioned(true);
setBaseLined(true);
setPath(null);
}
}
}

View File

@@ -0,0 +1,305 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVHandlerFactory;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVResponse;
import org.tmatesoft.svn.core.internal.server.dav.handlers.ServletDAVHandler;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVServlet extends HttpServlet {
public static final String XML_CONTENT_TYPE = "text/xml; charset=\"utf-8\"";
public static final String DAV_SVN_AUTOVERSIONING_ACTIVITY = "svn-autoversioning-activity";
private static final Map OUR_STATUS_LINES = new SVNHashMap();
private static final Map OUR_SHARED_CACHE = new SVNHashMap();
static {
OUR_STATUS_LINES.put(new Integer(100), "100 Continue");
OUR_STATUS_LINES.put(new Integer(101), "101 Switching Protocols");
OUR_STATUS_LINES.put(new Integer(102), "102 Processing");
OUR_STATUS_LINES.put(new Integer(200), "200 OK");
OUR_STATUS_LINES.put(new Integer(201), "201 Created");
OUR_STATUS_LINES.put(new Integer(202), "202 Accepted");
OUR_STATUS_LINES.put(new Integer(203), "203 Non-Authoritative Information");
OUR_STATUS_LINES.put(new Integer(204), "204 No Content");
OUR_STATUS_LINES.put(new Integer(205), "205 Reset Content");
OUR_STATUS_LINES.put(new Integer(206), "206 Partial Content");
OUR_STATUS_LINES.put(new Integer(207), "207 Multi-Status");
OUR_STATUS_LINES.put(new Integer(300), "300 Multiple Choices");
OUR_STATUS_LINES.put(new Integer(301), "301 Moved Permanently");
OUR_STATUS_LINES.put(new Integer(302), "302 Found");
OUR_STATUS_LINES.put(new Integer(303), "303 See Other");
OUR_STATUS_LINES.put(new Integer(304), "304 Not Modified");
OUR_STATUS_LINES.put(new Integer(305), "305 Use Proxy");
OUR_STATUS_LINES.put(new Integer(306), "306 unused");
OUR_STATUS_LINES.put(new Integer(307), "307 Temporary Redirect");
OUR_STATUS_LINES.put(new Integer(400), "400 Bad Request");
OUR_STATUS_LINES.put(new Integer(401), "401 Authorization Required");
OUR_STATUS_LINES.put(new Integer(402), "402 Payment Required");
OUR_STATUS_LINES.put(new Integer(403), "403 Forbidden");
OUR_STATUS_LINES.put(new Integer(404), "404 Not Found");
OUR_STATUS_LINES.put(new Integer(405), "405 Method Not Allowed");
OUR_STATUS_LINES.put(new Integer(406), "406 Not Acceptable");
OUR_STATUS_LINES.put(new Integer(407), "407 Proxy Authentication Required");
OUR_STATUS_LINES.put(new Integer(408), "408 Request Time-out");
OUR_STATUS_LINES.put(new Integer(409), "409 Conflict");
OUR_STATUS_LINES.put(new Integer(410), "410 Gone");
OUR_STATUS_LINES.put(new Integer(411), "411 Length Required");
OUR_STATUS_LINES.put(new Integer(412), "412 Precondition Failed");
OUR_STATUS_LINES.put(new Integer(413), "413 Request Entity Too Large");
OUR_STATUS_LINES.put(new Integer(414), "414 Request-URI Too Large");
OUR_STATUS_LINES.put(new Integer(415), "415 Unsupported Media Type");
OUR_STATUS_LINES.put(new Integer(416), "416 Requested Range Not Satisfiable");
OUR_STATUS_LINES.put(new Integer(417), "417 Expectation Failed");
OUR_STATUS_LINES.put(new Integer(418), "418 unused");
OUR_STATUS_LINES.put(new Integer(419), "419 unused");
OUR_STATUS_LINES.put(new Integer(420), "420 unused");
OUR_STATUS_LINES.put(new Integer(421), "421 unused");
OUR_STATUS_LINES.put(new Integer(422), "422 Unprocessable Entity");
OUR_STATUS_LINES.put(new Integer(423), "423 Locked");
OUR_STATUS_LINES.put(new Integer(424), "424 Failed Dependency");
OUR_STATUS_LINES.put(new Integer(425), "425 No code");
OUR_STATUS_LINES.put(new Integer(426), "426 Upgrade Required");
OUR_STATUS_LINES.put(new Integer(500), "500 Internal Server Error");
OUR_STATUS_LINES.put(new Integer(501), "501 Method Not Implemented");
OUR_STATUS_LINES.put(new Integer(502), "502 Bad Gateway");
OUR_STATUS_LINES.put(new Integer(503), "503 Service Temporarily Unavailable");
OUR_STATUS_LINES.put(new Integer(504), "504 Gateway Time-out");
OUR_STATUS_LINES.put(new Integer(505), "505 HTTP Version Not Supported");
OUR_STATUS_LINES.put(new Integer(506), "506 Variant Also Negotiates");
OUR_STATUS_LINES.put(new Integer(507), "507 Insufficient Storage");
OUR_STATUS_LINES.put(new Integer(508), "508 unused");
OUR_STATUS_LINES.put(new Integer(509), "509 unused");
OUR_STATUS_LINES.put(new Integer(510), "510 Not Extended");
}
private DAVConfig myDAVConfig;
// scm-mangager change
protected DAVConfig getDAVConfig() {
return myDAVConfig;
}
public void init() {
FSRepositoryFactory.setup();
try {
myDAVConfig = new DAVConfig(getServletConfig());
} catch (SVNException e) {
myDAVConfig = null;
}
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletDAVHandler handler = null;
logRequest(request);//TODO: remove later
try {
DAVRepositoryManager repositoryManager = new DAVRepositoryManager(getDAVConfig(), request);
handler = DAVHandlerFactory.createHandler(repositoryManager, request, response);
handler.execute();
} catch (DAVException de) {
response.setContentType(XML_CONTENT_TYPE);
handleError(de, response);
} catch (SVNException svne) {
StringWriter sw = new StringWriter();
svne.printStackTrace(new PrintWriter(sw));
String msg = sw.getBuffer().toString();
SVNErrorCode errorCode = svne.getErrorMessage().getErrorCode();
if (errorCode == SVNErrorCode.FS_NOT_DIRECTORY ||
errorCode == SVNErrorCode.FS_NOT_FOUND ||
errorCode == SVNErrorCode.RA_DAV_PATH_NOT_FOUND) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
} else if (errorCode == SVNErrorCode.NO_AUTH_FILE_PATH) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, msg);
} else if (errorCode == SVNErrorCode.RA_NOT_AUTHORIZED) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, msg);
} else {
String errorBody = generateStandardizedErrorBody(errorCode.getCode(), null, null, svne.getMessage());
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setContentType(XML_CONTENT_TYPE);
response.getWriter().print(errorBody);
}
} catch (Throwable th) {
StringWriter sw = new StringWriter();
th.printStackTrace(new PrintWriter(sw));
String msg = sw.getBuffer().toString();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
} finally {
response.flushBuffer();
}
}
private void logRequest(HttpServletRequest request) {
StringBuffer logBuffer = new StringBuffer();
logBuffer.append('\n');
logBuffer.append("request.getAuthType(): " + request.getAuthType());
logBuffer.append('\n');
logBuffer.append("request.getCharacterEncoding(): " + request.getCharacterEncoding());
logBuffer.append('\n');
logBuffer.append("request.getContentType(): " + request.getContentType());
logBuffer.append('\n');
logBuffer.append("request.getContextPath(): " + request.getContextPath());
logBuffer.append('\n');
logBuffer.append("request.getContentLength(): " + request.getContentLength());
logBuffer.append('\n');
logBuffer.append("request.getMethod(): " + request.getMethod());
logBuffer.append('\n');
logBuffer.append("request.getPathInfo(): " + request.getPathInfo());
logBuffer.append('\n');
logBuffer.append("request.getPathTranslated(): " + request.getPathTranslated());
logBuffer.append('\n');
logBuffer.append("request.getQueryString(): " + request.getQueryString());
logBuffer.append('\n');
logBuffer.append("request.getRemoteAddr(): " + request.getRemoteAddr());
logBuffer.append('\n');
logBuffer.append("request.getRemoteHost(): " + request.getRemoteHost());
logBuffer.append('\n');
logBuffer.append("request.getRemoteUser(): " + request.getRemoteUser());
logBuffer.append('\n');
logBuffer.append("request.getRequestURI(): " + request.getRequestURI());
logBuffer.append('\n');
logBuffer.append("request.getServerName(): " + request.getServerName());
logBuffer.append('\n');
logBuffer.append("request.getServerPort(): " + request.getServerPort());
logBuffer.append('\n');
logBuffer.append("request.getServletPath(): " + request.getServletPath());
logBuffer.append('\n');
logBuffer.append("request.getRequestURL(): " + request.getRequestURL());
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, logBuffer.toString());
}
public static void handleError(DAVException error, HttpServletResponse servletResponse) throws IOException {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, error);
DAVResponse response = error.getResponse();
if (response == null) {
DAVException stackErr = error;
while (stackErr != null && stackErr.getTagName() == null) {
stackErr = stackErr.getPreviousException();
}
if (stackErr != null && stackErr.getTagName() != null) {
servletResponse.setContentType(XML_CONTENT_TYPE);
servletResponse.setStatus(stackErr.getResponseCode());
StringBuffer errorMessageBuffer = new StringBuffer();
SVNXMLUtil.addXMLHeader(errorMessageBuffer);
errorMessageBuffer.append('\n');
errorMessageBuffer.append("<D:error xmlns:D=\"DAV:\"");
if (stackErr.getMessage() != null) {
errorMessageBuffer.append(" xmlns:m=\"http://apache.org/dav/xmlns\"");
}
if (stackErr.getNameSpace() != null) {
errorMessageBuffer.append(" xmlns:C=\"");
errorMessageBuffer.append(stackErr.getNameSpace());
errorMessageBuffer.append("\">\n<C:");
errorMessageBuffer.append(stackErr.getTagName());
errorMessageBuffer.append("/>");
} else {
errorMessageBuffer.append(">\n<D:");
errorMessageBuffer.append(stackErr.getTagName());
errorMessageBuffer.append("/>");
}
if (stackErr.getMessage() != null) {
errorMessageBuffer.append("<m:human-readable errcode=\"" );
errorMessageBuffer.append(stackErr.getErrorID());
errorMessageBuffer.append("\">\n");
errorMessageBuffer.append(SVNEncodingUtil.xmlEncodeCDATA(stackErr.getMessage()));
errorMessageBuffer.append('\n');
errorMessageBuffer.append("</m:human-readable>\n");
}
errorMessageBuffer.append("</D:error>\n");
servletResponse.getWriter().print(errorMessageBuffer.toString());
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, errorMessageBuffer.toString());
return;
}
servletResponse.setStatus(error.getResponseCode());
return;
}
DAVXMLUtil.sendMultiStatus(response, servletResponse, error.getResponseCode(), null);
}
private String generateStandardizedErrorBody(int errorID, String namespace, String tagName, String description) {
StringBuffer xmlBuffer = new StringBuffer();
SVNXMLUtil.addXMLHeader(xmlBuffer);
Collection namespaces = new ArrayList();
namespaces.add(DAVElement.DAV_NAMESPACE);
namespaces.add(DAVElement.SVN_APACHE_PROPERTY_NAMESPACE);
if (namespace != null) {
namespaces.add(namespace);
}
SVNXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVXMLUtil.SVN_DAV_ERROR_TAG, namespaces,
SVNXMLUtil.PREFIX_MAP, xmlBuffer);
String prefix = (String) SVNXMLUtil.PREFIX_MAP.get(namespace);
if (prefix != null) {
prefix = SVNXMLUtil.DAV_NAMESPACE_PREFIX;
}
if (tagName != null && tagName.length() > 0) {
SVNXMLUtil.openXMLTag(prefix, tagName, SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_APACHE_PROPERTY_PREFIX, "human-readable", SVNXMLUtil.XML_STYLE_NORMAL, "errcode",
String.valueOf(errorID), xmlBuffer);
xmlBuffer.append(SVNEncodingUtil.xmlEncodeCDATA(description));
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_APACHE_PROPERTY_PREFIX, "human-readable", xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVXMLUtil.SVN_DAV_ERROR_TAG, xmlBuffer);
return xmlBuffer.toString();
}
public static String getStatusLine(int statusCode) {
return (String) OUR_STATUS_LINES.get(new Integer(statusCode));
}
public static String getSharedActivity() {
synchronized (OUR_SHARED_CACHE) {
return (String) OUR_SHARED_CACHE.get(DAV_SVN_AUTOVERSIONING_ACTIVITY);
}
}
public static void setSharedActivity(String sharedActivity) {
synchronized (OUR_SHARED_CACHE) {
OUR_SHARED_CACHE.put(DAV_SVN_AUTOVERSIONING_ACTIVITY, sharedActivity);
}
}
public static boolean isHTTPServerError(int statusCode) {
return statusCode >= 500 && statusCode < 600;
}
}

View File

@@ -0,0 +1,440 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.fs.FSCommitter;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSID;
import org.tmatesoft.svn.core.internal.io.fs.FSNodeHistory;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionNode;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionRoot;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVServletUtil {
public static long getSafeCreatedRevision(FSRevisionRoot root, String path) {
long revision = root.getRevision();
FSFS fsfs = root.getOwner();
FSID id = null;
try {
FSRevisionNode node = root.getRevisionNode(path);
id = node.getId();
} catch (SVNException svne) {
return revision;
}
FSNodeHistory history = null;
long historyRev = -1;
try {
history = root.getNodeHistory(path);
history = history.getPreviousHistory(false);
historyRev = history.getHistoryEntry().getRevision();
} catch (SVNException svne) {
return revision;
}
FSRevisionRoot otherRoot = null;
try {
otherRoot = fsfs.createRevisionRoot(historyRev);
} catch (SVNException svne) {
return revision;
}
FSID otherID = null;
try {
FSRevisionNode node = otherRoot.getRevisionNode(path);
otherID = node.getId();
} catch (SVNException svne) {
return revision;
}
if (id.compareTo(otherID) == 0) {
return historyRev;
}
return revision;
}
public static URI lookUpURI(String uri, HttpServletRequest request, boolean mustBeAbsolute) throws DAVException {
URI parsedURI = null;
try {
parsedURI = new URI(uri);
} catch (URISyntaxException urise) {
throw new DAVException("Invalid syntax in Destination URI.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
if (parsedURI.getScheme() == null && mustBeAbsolute) {
throw new DAVException("Destination URI must be an absolute URI.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
if (parsedURI.getQuery() != null || parsedURI.getFragment() != null) {
throw new DAVException("Destination URI contains invalid components (a query or a fragment).", HttpServletResponse.SC_BAD_REQUEST, 0);
}
if (parsedURI.getScheme() != null || parsedURI.getPort() != -1 || mustBeAbsolute) {
String scheme = request.getScheme();
if (scheme == null) {
//TODO: replace this code in future
scheme = "http";
}
int parsedPort = parsedURI.getPort();
if (parsedURI.getPort() == -1) {
parsedPort = request.getServerPort();
}
if (!scheme.equals(parsedURI.getScheme()) || parsedPort != request.getServerPort()) {
throw new DAVException("Destination URI refers to different scheme or port ({0}://hostname:{1})\n(want: {2}://hostname:{3})",
new Object[] { parsedURI.getScheme() != null ? parsedURI.getScheme() : scheme, String.valueOf(parsedPort), scheme,
String.valueOf(request.getServerPort()) }, HttpServletResponse.SC_BAD_REQUEST, 0);
}
}
String parsedHost = parsedURI.getHost();
String serverHost = request.getServerName();
String domain = null;
int domainInd = serverHost != null ? serverHost.indexOf('.') : -1;
if (domainInd != -1) {
domain = serverHost.substring(domainInd);
}
if (parsedHost != null && parsedHost.indexOf('.') == -1 && domain != null) {
parsedHost += domain;
}
if (parsedHost != null && !parsedHost.equals(request.getServerName())) {
throw new DAVException("Destination URI refers to a different server.", HttpServletResponse.SC_BAD_GATEWAY, 0);
}
return parsedURI;
}
public static void setAutoRevisionProperties(DAVResource resource) throws DAVException {
if (!(resource.getType() == DAVResourceType.WORKING && resource.isAutoCheckedOut())) {
throw new DAVException("Set_auto_revprops called on invalid resource.", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
try {
attachAutoRevisionProperties(resource.getTxnInfo(), resource.getResourceURI().getPath(), resource.getFSFS());
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error setting a revision property ", null);
}
}
public static void attachAutoRevisionProperties(FSTransactionInfo txn, String path, FSFS fsfs) throws SVNException {
String logMessage = "Autoversioning commit: a non-deltaV client made a change to\n" + path;
SVNProperties props = new SVNProperties();
props.put(SVNRevisionProperty.LOG, logMessage);
props.put(SVNRevisionProperty.AUTOVERSIONED, "*");
fsfs.changeTransactionProperties(txn.getTxnId(), props);
}
public static void deleteActivity(DAVResource resource, String activityID) throws DAVException {
File activitiesDB = resource.getActivitiesDB();
String txnName = getTxn(activitiesDB, activityID);
if (txnName == null) {
throw new DAVException("could not find activity.", HttpServletResponse.SC_NOT_FOUND, 0);
}
FSFS fsfs = resource.getFSFS();
FSTransactionInfo txn = null;
if (txnName != null) {
try {
txn = fsfs.openTxn(txnName);
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() != SVNErrorCode.FS_NO_SUCH_TRANSACTION) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not open transaction.", null);
}
}
if (txn != null) {
try {
FSCommitter.abortTransaction(fsfs, txn.getTxnId());
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not abort transaction.", null);
}
}
}
try {
SVNFileUtil.deleteFile(DAVPathUtil.getActivityPath(activitiesDB, activityID));
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"unable to remove activity.", null);
}
}
public static void storeActivity(DAVResource resource, String txnName) throws DAVException {
DAVResourceURI resourceURI = resource.getResourceURI();
String activityID = resourceURI.getActivityID();
File activitiesDB = resource.getActivitiesDB();
if (!activitiesDB.exists() && !activitiesDB.mkdirs()) {
throw new DAVException("could not initialize activity db.", null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null,
SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
File finalActivityFile = DAVPathUtil.getActivityPath(activitiesDB, activityID);
File tmpFile = null;
try {
tmpFile = SVNFileUtil.createUniqueFile(finalActivityFile.getParentFile(), finalActivityFile.getName(), "tmp", false);
} catch (SVNException svne) {
SVNErrorMessage err = svne.getErrorMessage().wrap("Can't open activity db");
throw DAVException.convertError(err, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "could not open files.", null);
}
StringBuffer activitiesContents = new StringBuffer();
activitiesContents.append(txnName);
activitiesContents.append('\n');
activitiesContents.append(activityID);
activitiesContents.append('\n');
try {
SVNFileUtil.writeToFile(tmpFile, activitiesContents.toString(), null);
} catch (SVNException svne) {
SVNErrorMessage err = svne.getErrorMessage().wrap("Can't write to activity db");
try {
SVNFileUtil.deleteFile(tmpFile);
} catch (SVNException e) {
}
throw DAVException.convertError(err, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "could not write files.", null);
}
try {
SVNFileUtil.rename(tmpFile, finalActivityFile);
} catch (SVNException svne) {
try {
SVNFileUtil.deleteFile(tmpFile);
} catch (SVNException e) {
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "could not replace files.", null);
}
}
public static FSTransactionInfo createActivity(DAVResource resource, FSFS fsfs) throws DAVException {
SVNProperties properties = new SVNProperties();
properties.put(SVNRevisionProperty.AUTHOR, resource.getUserName());
long revision = SVNRepository.INVALID_REVISION;
try {
revision = fsfs.getYoungestRevision();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not determine youngest revision", null);
}
FSTransactionInfo txnInfo = null;
try {
txnInfo = FSTransactionRoot.beginTransactionForCommit(revision, properties, fsfs);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not begin a transaction", null);
}
return txnInfo;
}
public static LinkedList processIfHeader(String value) throws DAVException {
if (value == null) {
return null;
}
StringBuffer valueBuffer = new StringBuffer(value);
ListType listType = ListType.UNKNOWN;
String uri = null;
LinkedList ifHeaders = new LinkedList();
DAVIFHeader ifHeader = null;
while (valueBuffer.length() > 0) {
if (valueBuffer.charAt(0) == '<') {
if (listType == ListType.NO_TAGGED || (uri = DAVServletUtil.fetchNextToken(valueBuffer, '>')) == null) {
throw new DAVException("Invalid If-header: unclosed \"<\" or unexpected tagged-list production.",
HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_TAGGED);
}
URI parsedURI = null;
try {
parsedURI = new URI(uri);
} catch (URISyntaxException urise) {
throw new DAVException("Invalid URI in tagged If-header.", HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_TAGGED);
}
uri = parsedURI.getPath();
uri = uri.length() > 1 && uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
listType = ListType.TAGGED;
} else if (valueBuffer.charAt(0) == '(') {
if (listType == ListType.UNKNOWN) {
listType = ListType.NO_TAGGED;
}
StringBuffer listBuffer = null;
String list = null;
if ((list = DAVServletUtil.fetchNextToken(valueBuffer, ')')) == null) {
throw new DAVException("Invalid If-header: unclosed \"(\".", HttpServletResponse.SC_BAD_REQUEST,
DAVErrorCode.IF_UNCLOSED_PAREN);
}
ifHeader = new DAVIFHeader(uri);
ifHeaders.addFirst(ifHeader);
int condition = DAVIFState.IF_CONDITION_NORMAL;
String stateToken = null;
listBuffer = new StringBuffer(list);
while (listBuffer.length() > 0) {
if (listBuffer.charAt(0) == '<') {
if ((stateToken = DAVServletUtil.fetchNextToken(listBuffer, '>')) == null) {
throw new DAVException(null, HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_PARSE);
}
addIfState(stateToken, DAVIFStateType.IF_OPAQUE_LOCK, condition, ifHeader);
condition = DAVIFState.IF_CONDITION_NORMAL;
} else if (listBuffer.charAt(0) == '[') {
if ((stateToken = fetchNextToken(listBuffer, ']')) == null) {
throw new DAVException(null, HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_PARSE);
}
addIfState(stateToken, DAVIFStateType.IF_ETAG, condition, ifHeader);
condition = DAVIFState.IF_CONDITION_NORMAL;
} else if (listBuffer.charAt(0) == 'N') {
if (listBuffer.length() > 2 && listBuffer.charAt(1) == 'o' && listBuffer.charAt(2) == 't') {
if (condition != DAVIFState.IF_CONDITION_NORMAL) {
throw new DAVException("Invalid \"If:\" header: Multiple \"not\" entries for the same state.",
HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_MULTIPLE_NOT);
}
condition = DAVIFState.IF_CONDITION_NOT;
}
listBuffer.delete(0, 2);
} else if (listBuffer.charAt(0) != ' ' && listBuffer.charAt(0) != '\t') {
throw new DAVException("Invalid \"If:\" header: Unexpected character encountered ({0}, ''{1}'').",
new Object[] { Integer.toHexString(listBuffer.charAt(0)), new Character(listBuffer.charAt(0)) },
HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_UNK_CHAR);
}
listBuffer.deleteCharAt(0);
}
} else if (valueBuffer.charAt(0) != ' ' && valueBuffer.charAt(0) != '\t') {
throw new DAVException("Invalid \"If:\" header: Unexpected character encountered ({0}, ''{1}'').",
new Object[] { Integer.toHexString(valueBuffer.charAt(0)), new Character(valueBuffer.charAt(0)) },
HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.IF_UNK_CHAR);
}
valueBuffer.deleteCharAt(0);
}
return ifHeaders;
}
public static FSTransactionInfo openTxn(FSFS fsfs, String txnName) throws DAVException {
FSTransactionInfo txnInfo = null;
try {
txnInfo = fsfs.openTxn(txnName);
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NO_SUCH_TRANSACTION) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"The transaction specified by the activity does not exist", null);
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"There was a problem opening the transaction specified by this activity.", null);
}
return txnInfo;
}
public static String getTxn(File activitiesDB, String activityID) {
File activityFile = DAVPathUtil.getActivityPath(activitiesDB, activityID);
return DAVServletUtil.readTxn(activityFile);
}
public static String readTxn(File activityFile) {
String txnName = null;
for (int i = 0; i < 10; i++) {
try {
txnName = SVNFileUtil.readSingleLine(activityFile);
} catch (IOException e) {
//ignore
}
}
return txnName;
}
public static SVNNodeKind checkPath(FSRoot root, String path) throws DAVException {
try {
return root.checkNodeKind(path);
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NOT_DIRECTORY) {
return SVNNodeKind.NONE;
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error checking kind of path ''{0}'' in repository", new Object[] { path });
}
}
private static void addIfState(String stateToken, DAVIFStateType type, int condition, DAVIFHeader ifHeader) {
String eTag = null;
String lockToken = null;
if (type == DAVIFStateType.IF_OPAQUE_LOCK) {
lockToken = stateToken;
} else {
eTag = stateToken;
}
DAVIFState ifState = new DAVIFState(condition, eTag, lockToken, type);
ifHeader.addIFState(ifState);
}
private static String fetchNextToken(StringBuffer string, char term) {
String token = string.substring(1);
token = token.trim();
int ind = -1;
if ((ind = token.indexOf(term)) == -1) {
return null;
}
token = token.substring(0, ind);
string.delete(0, string.indexOf(token) + token.length());
return token;
}
private static class ListType {
public static final ListType NO_TAGGED = new ListType();
public static final ListType TAGGED = new ListType();
public static final ListType UNKNOWN = new ListType();
private ListType() {
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVURIInfo {
private long myRevision;
private String myActivityID;
private String myRepositoryPath;
public DAVURIInfo(String activityID, String repositoryPath, long revision) {
myActivityID = activityID;
myRepositoryPath = repositoryPath;
myRevision = revision;
}
public long getRevision() {
return myRevision;
}
public String getActivityID() {
return myActivityID;
}
public String getRepositoryPath() {
return myRepositoryPath;
}
}

View File

@@ -0,0 +1,75 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.wc.SVNRevision;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVVersionResourceHelper extends DAVResourceHelper {
protected void prepare(DAVResource resource) throws DAVException {
if (!SVNRevision.isValidRevisionNumber(resource.getRevision())) {
try {
resource.setRevision(resource.getLatestRevision());
} catch (SVNException e) {
throw DAVException.convertError(e.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not fetch 'youngest' revision to enable accessing the latest baseline resource.", null);
}
}
FSRoot root = resource.getRoot();
FSFS fsfs = resource.getFSFS();
if (root == null) {
try {
root = fsfs.createRevisionRoot(resource.getRevision());
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not open a revision root.", null);
}
resource.setRoot(root);
}
resource.getResourceURI().setURI(DAVPathUtil.buildURI(null, DAVResourceKind.BASELINE, resource.getRevision(), null, false));
resource.setExists(true);
}
protected DAVResource getParentResource(DAVResource resource) throws DAVException {
DAVResourceHelper.throwIllegalGetParentResourceError(resource);
return null;
}
public static DAVResource createVersionResource(DAVResource resource, String uri) throws DAVException {
DAVResourceURI regularResourceURI = null;
try {
regularResourceURI = new DAVResourceURI(resource.getResourceURI().getContext(), uri, null, false);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not parse version resource uri.", null);
}
return new DAVResource(resource.getRepository(), resource.getRepositoryManager(), regularResourceURI, resource.isSVNClient(),
resource.getDeltaBase(), resource.getVersion(), resource.getClientOptions(), resource.getBaseChecksum(),
resource.getResultChecksum(), resource.getUserName(), resource.getActivitiesDB(), resource.getLockTokens(),
resource.getClientCapabilities());
}
}

View File

@@ -0,0 +1,148 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVWorkingResourceHelper extends DAVResourceHelper {
protected void prepare(DAVResource resource) throws DAVException {
String txnName = DAVServletUtil.getTxn(resource.getActivitiesDB(), resource.getResourceURI().getActivityID());
if (txnName == null) {
throw new DAVException("An unknown activity was specified in the URL. This is generally caused by a problem in the client software.",
null, HttpServletResponse.SC_BAD_REQUEST, null, SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
resource.setTxnName(txnName);
FSFS fsfs = resource.getFSFS();
FSTransactionInfo txnInfo = null;
try {
txnInfo = fsfs.openTxn(txnName);
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NO_SUCH_TRANSACTION) {
throw new DAVException("An activity was specified and found, but the corresponding SVN FS transaction was not found.",
null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"An activity was specified and found, but the corresponding SVN FS transaction was not found.", null);
}
resource.setTxnInfo(txnInfo);
if (resource.isBaseLined()) {
resource.setExists(true);
return;
}
String userName = resource.getUserName();
if (resource.getUserName() != null) {
SVNProperties props = null;
try {
props = fsfs.getTransactionProperties(txnName);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to retrieve author of the SVN FS transaction corresponding to the specified activity.", null);
}
String currentAuthor = props.getStringValue(SVNRevisionProperty.AUTHOR);
if (currentAuthor == null) {
try {
fsfs.setTransactionProperty(txnName, SVNRevisionProperty.AUTHOR, SVNPropertyValue.create(userName));
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to set the author of the SVN FS transaction corresponding to the specified activity.", null);
}
} else if (!currentAuthor.equals(userName)) {
throw new DAVException("Multi-author commits not supported.", null, HttpServletResponse.SC_NOT_IMPLEMENTED, null,
SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
}
FSRoot root = null;
try {
root = fsfs.createTransactionRoot(txnInfo);
resource.setRoot(root);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not open the (transaction) root of the repository", null);
}
SVNNodeKind kind = DAVServletUtil.checkPath(root, resource.getResourceURI().getPath());
resource.setExists(kind != SVNNodeKind.NONE);
resource.setCollection(kind == SVNNodeKind.DIR);
}
protected DAVResource getParentResource(DAVResource resource) throws DAVException {
return DAVPrivateResourceHelper.createPrivateResource(resource, DAVResourceKind.WORKING);
}
public static DAVResource createWorkingResource(DAVResource baseResource, String activityID, String txnName, boolean inPlace) {
StringBuffer pathBuffer = new StringBuffer();
if (baseResource.isBaseLined()) {
pathBuffer.append('/');
pathBuffer.append(DAVResourceURI.SPECIAL_URI);
pathBuffer.append("/wbl/");
pathBuffer.append(activityID);
pathBuffer.append('/');
pathBuffer.append(baseResource.getRevision());
} else {
pathBuffer.append('/');
pathBuffer.append(DAVResourceURI.SPECIAL_URI);
pathBuffer.append("/wrk/");
pathBuffer.append(activityID);
pathBuffer.append(baseResource.getResourceURI().getPath());
}
String uriPath = SVNEncodingUtil.uriEncode(pathBuffer.toString());
DAVResource resource = null;
if (inPlace) {
resource = baseResource;
} else {
resource = new DAVResource();
baseResource.copyTo(resource);
}
resource.setTxnName(txnName);
resource.setExists(true);
resource.setVersioned(true);
resource.setWorking(true);
DAVResourceURI uri = resource.getResourceURI();
uri.setType(DAVResourceType.WORKING);
uri.setURI(uriPath);
uri.setActivityID(activityID);
return resource;
}
}

View File

@@ -0,0 +1,185 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVPropsResult;
import org.tmatesoft.svn.core.internal.server.dav.handlers.DAVResponse;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVXMLUtil extends SVNXMLUtil {
public static final String SVN_DAV_ERROR_TAG = "error";
public static StringBuffer addEmptyElement(List namespaces, DAVElement element, StringBuffer target) {
if (element.getNamespace() == null || "".equals(element.getNamespace())) {
target.append("<");
target.append(element.getName());
target.append("/>");
target.append('\n');
return target;
}
int index = namespaces.indexOf(element.getNamespace());
target.append("<ns");
target.append(index);
target.append(":");
target.append(element.getName());
target.append("/>");
return target;
}
public static StringBuffer openNamespaceDeclarationTag(String prefix, String header, Collection namespaces, StringBuffer target,
boolean useIndexedPrefixes) {
return openNamespaceDeclarationTag(prefix, header, namespaces, null, target, true, useIndexedPrefixes);
}
public static StringBuffer openNamespaceDeclarationTag(String prefix, String header, Collection namespaces, Map attrs,
StringBuffer target, boolean addEOL, boolean useIndexedPrefixes) {
target = target == null ? new StringBuffer() : target;
target.append("<");
target.append(prefix);
target.append(":");
target.append(header);
//We should always add "DAV:" namespace
target.append(" xmlns:");
target.append(DAV_NAMESPACE_PREFIX);
target.append("=\"");
target.append(DAVElement.DAV_NAMESPACE);
target.append("\"");
if (namespaces != null && !namespaces.isEmpty()) {
Collection usedNamespaces = new ArrayList();
usedNamespaces.add(DAVElement.DAV_NAMESPACE);
int i = 0;
for (Iterator iterator = namespaces.iterator(); iterator.hasNext();) {
Object item = iterator.next();
String currentNamespace = null;
if (item instanceof DAVElement) {
DAVElement currentElement = (DAVElement) item;
currentNamespace = currentElement.getNamespace();
} else if (item instanceof String) {
currentNamespace = (String) item;
}
if (currentNamespace != null && currentNamespace.length() > 0 && (useIndexedPrefixes ||
!usedNamespaces.contains(currentNamespace))) {
usedNamespaces.add(currentNamespace);
target.append(" xmlns:");
if (useIndexedPrefixes) {
target.append("ns" + i);
} else {
target.append(PREFIX_MAP.get(currentNamespace));
}
target.append("=\"");
target.append(currentNamespace);
target.append("\"");
}
i++;
}
usedNamespaces.clear();
}
if (attrs != null && !attrs.isEmpty()) {
for (Iterator iterator = attrs.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String name = (String) entry.getKey();
String value = (String) entry.getValue();
target.append(" ");
target.append(name);
target.append("=\"");
target.append(SVNEncodingUtil.xmlEncodeAttr(value));
target.append("\"");
}
}
target.append(">");
if (addEOL) {
target.append('\n');
}
return target;
}
public static StringBuffer beginMultiStatus(HttpServletResponse servletResponse, int status, Collection namespaces, StringBuffer xmlBuffer) {
servletResponse.setContentType(DAVServlet.XML_CONTENT_TYPE);
servletResponse.setStatus(status);
xmlBuffer = xmlBuffer == null ? new StringBuffer() : xmlBuffer;
SVNXMLUtil.addXMLHeader(xmlBuffer);
DAVXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.MULTISTATUS.getName(), namespaces, xmlBuffer,
namespaces != null);
return xmlBuffer;
}
public static void sendMultiStatus(DAVResponse davResponse, HttpServletResponse servletResponse, int statusCode,
Collection namespaces) throws IOException {
StringBuffer xmlBuffer = new StringBuffer();
xmlBuffer = beginMultiStatus(servletResponse, statusCode, namespaces, xmlBuffer);
while (davResponse != null) {
sendOneResponse(davResponse, xmlBuffer);
davResponse = davResponse.getNextResponse();
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.MULTISTATUS.getName(), xmlBuffer);
servletResponse.getWriter().write(xmlBuffer.toString());
}
public static void sendOneResponse(DAVResponse davResponse, StringBuffer xmlBuffer) {
DAVPropsResult propResult = davResponse.getPropResult();
Collection namespaces = propResult.getNamespaces();
if (namespaces == null || namespaces.isEmpty()) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null,
xmlBuffer);
} else {
xmlBuffer.append('<');
xmlBuffer.append(SVNXMLUtil.DAV_NAMESPACE_PREFIX);
xmlBuffer.append(':');
xmlBuffer.append(DAVElement.RESPONSE.getName());
for (Iterator namespacesIter = namespaces.iterator(); namespacesIter.hasNext();) {
String namespaceText = (String) namespacesIter.next();
xmlBuffer.append(namespaceText);
}
xmlBuffer.append(">\n");
}
String href = davResponse.getHref();
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), href, null, true, true, xmlBuffer);
String propStatsText = propResult.getPropStatsText();
if (propStatsText == null || propStatsText.length() == 0) {
String statusLine = "HTTP/1.1 " + DAVServlet.getStatusLine(davResponse.getStatusCode());
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), statusLine, null, false, false, xmlBuffer);
} else {
xmlBuffer.append(propStatsText);
}
if (davResponse.getDescription() != null) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE_DESCRIPTION.getName(), davResponse.getDescription(),
null, false, false, xmlBuffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE.getName(), xmlBuffer);
}
}

View File

@@ -0,0 +1,674 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Pattern;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslatorInputStream;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class SVNPathBasedAccess {
private static final Pattern COMMA = Pattern.compile(",");
private static final String ANONYMOUS_REPOSITORY = "";
public static final int SVN_ACCESS_NONE = 0;
public static final int SVN_ACCESS_READ = 1;
public static final int SVN_ACCESS_WRITE = 2;
public static final int SVN_ACCESS_RECURSIVE = 4;
private String myConfigPath;
private int myCurrentLineNumber = 1;
private int myCurrentLineColumn = 0;
private char myUngottenChar = 0;
private boolean myHasUngottenChar = false;
private StringBuffer mySectionName;
private StringBuffer myOption;
private StringBuffer myValue;
private Map myGroups;
private Map myAliases;
private Map myRules;
public SVNPathBasedAccess(File pathBasedAccessConfiguration) throws SVNException {
myConfigPath = pathBasedAccessConfiguration.getAbsolutePath();
InputStream stream = null;
try {
stream = new SVNTranslatorInputStream(SVNFileUtil.openFileForReading(pathBasedAccessConfiguration, SVNLogType.NETWORK), SVNProperty.EOL_LF_BYTES, true, null, false);
} catch (SVNException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "Failed to load the AuthzSVNAccessFile: ''{0}''", pathBasedAccessConfiguration.getAbsolutePath()), SVNLogType.NETWORK);
}
try {
parse(stream);
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e.getLocalizedMessage()), SVNLogType.NETWORK);
}
validate();
}
private String getConfigPath() {
return myConfigPath;
}
private void increaseCurrentLineNumber() {
myCurrentLineNumber++;
}
private int getCurrentLineNumber() {
return myCurrentLineNumber;
}
private void increaseCurrentLineColumn() {
myCurrentLineColumn++;
}
private void resetCurrentLineColumn() {
myCurrentLineColumn = 0;
}
private int getCurrentLineColumn() {
return myCurrentLineColumn;
}
private char getUngottenChar() {
return myUngottenChar;
}
private void setUngottenChar(char ungottenChar) {
myUngottenChar = ungottenChar;
}
private boolean hasUngottenChar() {
return myHasUngottenChar;
}
private void setHasUngottenChar(boolean hasUngottenChar) {
myHasUngottenChar = hasUngottenChar;
}
private StringBuffer getSectionName() {
if (mySectionName == null) {
mySectionName = new StringBuffer();
}
return mySectionName;
}
private StringBuffer getOption() {
if (myOption == null) {
myOption = new StringBuffer();
}
return myOption;
}
private StringBuffer getValue() {
if (myValue == null) {
myValue = new StringBuffer();
}
return myValue;
}
private Map getGroups() {
if (myGroups == null) {
myGroups = new SVNHashMap();
}
return myGroups;
}
private boolean groupContainsUser(String group, String user) {
String[] groupUsers = (String[]) getGroups().get(group);
if (groupUsers == null) {
return false;
}
for (int i = 0; i < groupUsers.length; i++) {
if (groupUsers[i].startsWith("@")) {
if (groupContainsUser(groupUsers[i].substring("@".length()), user)) {
return true;
}
} else if (groupUsers[i].startsWith("&")) {
if (aliasIsUser(groupUsers[i].substring("&".length()), user)) {
return true;
}
} else if (groupUsers[i].equals(user)) {
return true;
}
}
return false;
}
private Map getAliases() {
if (myAliases == null) {
myAliases = new SVNHashMap();
}
return myAliases;
}
private boolean aliasIsUser(String alias, String user) {
String aliasValue = (String) getAliases().get(alias);
return aliasValue != null && aliasValue.equals(user);
}
private Map getRules() {
if (myRules == null) {
myRules = new SVNHashMap();
}
return myRules;
}
public boolean checkAccess(String repository, String path, String user, int access) {
RepositoryAccess repositoryAccess = (RepositoryAccess) getRules().get(repository);
if (repositoryAccess == null) {
repositoryAccess = (SVNPathBasedAccess.RepositoryAccess) getRules().get(ANONYMOUS_REPOSITORY);
if (repositoryAccess == null) {
return false;
}
}
return repositoryAccess.checkPathAccess(path, user, access);
}
private void parse(InputStream is) throws IOException, SVNException {
boolean isEOF = false;
int currentByte;
do {
currentByte = skipWhitespace(is);
switch (currentByte) {
case'[':
if (getCurrentLineColumn() == 0) {
parseSectionName(is);
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "''{0}'' : ''{1}'' : Section header must start in the first column.", new Object[]{getConfigPath(), new Integer(getCurrentLineNumber())}), SVNLogType.NETWORK);
}
break;
case'#':
if (getCurrentLineColumn() == 0) {
skipToEndOfLine(is);
increaseCurrentLineNumber();
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "''{0}'' : ''{1}'' : Comment must start in the first column.", new Object[]{getConfigPath(), new Integer(getCurrentLineNumber())}), SVNLogType.NETWORK);
}
break;
case'\n':
increaseCurrentLineNumber();
break;
case-1:
isEOF = true;
break;
default:
if (getSectionName().length() == 0) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "''{0}'' : ''{1}'' : Section header expected.", new Object[]{getConfigPath(), new Integer(getCurrentLineNumber())}), SVNLogType.NETWORK);
} else if (getCurrentLineColumn() != 0) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "''{0}'' : ''{1}'' : Option expected.", new Object[]{getConfigPath(), new Integer(getCurrentLineNumber())}), SVNLogType.NETWORK);
} else {
parseOption(is, currentByte);
}
}
} while (!isEOF);
getSectionName().setLength(0);
getOption().setLength(0);
getValue().setLength(0);
}
private int parseSectionName(InputStream is) throws IOException, SVNException {
getSectionName().setLength(0);
int currentByte = getc(is);
while (currentByte != -1 && currentByte != '\n' && currentByte != ']') {
getSectionName().append((char) currentByte);
currentByte = getc(is);
}
if (currentByte != ']') {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "''{0}'' : ''{1}'' : Section header must end with ']'.", new Object[]{getConfigPath(), new Integer(getCurrentLineNumber())}), SVNLogType.NETWORK);
} else {
currentByte = skipToEndOfLine(is);
if (currentByte != -1) {
increaseCurrentLineNumber();
}
}
return currentByte;
}
private int parseOption(InputStream is, int firstByte) throws IOException, SVNException {
getOption().setLength(0);
int currentByte = firstByte;
while (currentByte != -1 && currentByte != ':' && currentByte != '=' && currentByte != '\n') {
getOption().append((char) currentByte);
currentByte = getc(is);
}
if (currentByte != ':' && currentByte != '=') {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "''{0}'' : ''{1}'' : Option must end with ':' or '='.", new Object[]{getConfigPath(), new Integer(getCurrentLineNumber())}), SVNLogType.NETWORK);
} else {
trimBuffer(getOption());
currentByte = parseValue(is);
}
return currentByte;
}
private int parseValue(InputStream is) throws IOException, SVNException {
getValue().setLength(0);
int currentByte = getc(is);
boolean isEndOfValue = false;
while (currentByte != -1 && currentByte != '\n') {
getValue().append((char) currentByte);
currentByte = getc(is);
}
trimBuffer(getValue());
while (true) {
if (currentByte == -1 || isEndOfValue) {
updateConfiguration();
break;
}
increaseCurrentLineNumber();
currentByte = skipWhitespace(is);
switch (currentByte) {
case'\n':
increaseCurrentLineNumber();
isEndOfValue = true;
continue;
case-1:
isEndOfValue = true;
continue;
default:
if (getCurrentLineColumn() == 0) {
ungetc((char) currentByte);
isEndOfValue = true;
} else {
//Continuation line found.
getValue().append(' ');
while (currentByte != -1 && currentByte != '\n') {
getValue().append((char) currentByte);
currentByte = getc(is);
}
trimBuffer(getValue());
}
}
}
return currentByte;
}
private int skipWhitespace(InputStream is) throws IOException {
resetCurrentLineColumn();
int currentByte = getc(is);
while (Character.isWhitespace((char) currentByte)) {
currentByte = getc(is);
increaseCurrentLineColumn();
}
return currentByte;
}
private int skipToEndOfLine(InputStream is) throws IOException {
int currentByte = getc(is);
while (currentByte != -1 && currentByte != '\n') {
currentByte = getc(is);
resetCurrentLineColumn();
}
return currentByte;
}
private int getc(InputStream is) throws IOException {
if (hasUngottenChar()) {
setHasUngottenChar(false);
return getUngottenChar();
}
return is.read();
}
private void ungetc(char ungottenChar) {
setUngottenChar(ungottenChar);
setHasUngottenChar(true);
}
private void trimBuffer(StringBuffer buffer) {
while (buffer.length() > 0 && Character.isWhitespace(buffer.charAt(0))) {
buffer.deleteCharAt(0);
}
while (buffer.length() > 0 && Character.isWhitespace(buffer.charAt(buffer.length() - 1))) {
buffer.deleteCharAt(buffer.length() - 1);
}
}
private void updateConfiguration() throws SVNException {
if ("groups".equals(getSectionName().toString())) {
updateGroups();
} else if ("aliases".equals(getSectionName().toString())) {
updateAliases();
} else {
updateRules();
}
}
private void updateGroups() throws SVNException {
String groupName = getOption().toString();
if (getValue().length() == 0) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An authz rule refers to group ''{0}'', which is undefined", groupName), SVNLogType.NETWORK);
}
String[] users = COMMA.split(getValue());
getGroups().put(groupName, users);
}
private void updateAliases() throws SVNException {
String alias = getOption().toString();
if (getValue().length() == 0) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An authz rule refers to alies ''{0}'', which is undefined", alias), SVNLogType.NETWORK);
}
getAliases().put(alias, getValue().toString());
}
private void updateRules() throws SVNException {
int delimeterIndex = getSectionName().indexOf(":");
String repositoryName = delimeterIndex == -1 ? ANONYMOUS_REPOSITORY : getSectionName().substring(0, delimeterIndex);
String path = delimeterIndex == -1 ? getSectionName().toString() : getSectionName().substring(delimeterIndex + 1);
String value = getValue().toString();
if (getOption().charAt(0) == '~') {
if (getOption().charAt(1) == '~') {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "Rule ''{0}'' has more than one inversion; double negatives are not permitted.", getOption()), SVNLogType.NETWORK);
}
if (getOption().charAt(1) == '*') {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "Authz rules with match string '~*' are not allowed, because they never match anyone."), SVNLogType.NETWORK);
}
}
if (getOption().charAt(0) == '$') {
String token = getOption().substring(1);
if (!"anonymous".equals(token) && !"authenticated".equals(token)) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "Unrecognized authz token ''{0}''.", getOption()), SVNLogType.NETWORK);
}
}
if (value.length() > 0 && !"r".equals(value) && !"rw".equals(value)) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "The value ''{0}'' in rule ''{1}'' is not allowed in authz rules.", new Object[]{value, getOption()}), SVNLogType.NETWORK);
}
RepositoryAccess repositoryAccess = (RepositoryAccess) getRules().get(repositoryName);
if (repositoryAccess == null) {
repositoryAccess = new RepositoryAccess(ANONYMOUS_REPOSITORY.equals(repositoryName));
getRules().put(repositoryName, repositoryAccess);
}
repositoryAccess.addRule(path, getOption().toString(), getValue().toString());
}
private void validate() throws SVNException {
Collection checkedPathes = new ArrayList();
for (Iterator iterator = getGroups().keySet().iterator(); iterator.hasNext();) {
String groupName = (String) iterator.next();
checkedPathes.clear();
groupWalk(groupName, checkedPathes);
}
for (Iterator repositories = getRules().values().iterator(); repositories.hasNext();) {
RepositoryAccess repositoryAccess = (RepositoryAccess) repositories.next();
repositoryAccess.validateRules();
}
}
private void groupWalk(String group, Collection checkedGroups) throws SVNException {
String[] users = (String[]) getGroups().get(group);
if (users == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An authz rule refers to group ''{0}'', which is undefined.", group), SVNLogType.NETWORK);
}
for (int i = 0; i < users.length; i++) {
users[i] = users[i].trim();
if (users[i].startsWith("@")) {
String subGroup = users[i].substring("@".length());
if (checkedGroups.contains(subGroup)) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "Circular dependency between groups ''{0}'' and ''{1}''", new Object[]{group, subGroup}), SVNLogType.NETWORK);
}
checkedGroups.add(subGroup);
groupWalk(subGroup, checkedGroups);
checkedGroups.remove(subGroup);
} else if (users[i].startsWith("&")) {
String alias = users[i].substring("&".length());
if (!getAliases().keySet().contains(alias)) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An authz rule refers to alias ''{0}'', which is undefined.", alias), SVNLogType.NETWORK);
}
}
}
}
private class RepositoryAccess {
boolean myAnonymous = false;
private Map myPathRules;
private PathAccess myGlobalAccess;
private RepositoryAccess(boolean isAnonymous) {
myAnonymous = isAnonymous;
}
private void addRule(String path, String matchString, String value) {
if (path.equals("/") || path.length() == 0) {
myGlobalAccess = myGlobalAccess == null ? new PathAccess() : myGlobalAccess;
myGlobalAccess.addRule(matchString, value);
}
myPathRules = myPathRules == null ? new SVNHashMap() : myPathRules;
PathAccess pathAccess = (PathAccess) myPathRules.get(path);
if (pathAccess == null) {
pathAccess = new PathAccess();
myPathRules.put(path, pathAccess);
}
pathAccess.addRule(matchString, value);
}
private void validateRules() throws SVNException {
if (myGlobalAccess != null) {
myGlobalAccess.validateRules();
}
if (myPathRules != null) {
for (Iterator iterator = myPathRules.values().iterator(); iterator.hasNext();) {
PathAccess pathAccess = (PathAccess) iterator.next();
pathAccess.validateRules();
}
}
}
private boolean checkPathAccess(String path, String user, int requestedAccess) {
boolean accessGranted = false;
if (path == null || path.length() == 0 || "/".equals(path)) {
if (myGlobalAccess != null) {
int[] pathAccess = myGlobalAccess.checkAccess(user);
if (isAccessDetermined(pathAccess, requestedAccess)) {
accessGranted = isAccessGranted(pathAccess, requestedAccess);
}
}
} else {
if (myPathRules == null) {
return false;
}
int[] pathAccess = checkCurrentPath(path, user);
if (isAccessDetermined(pathAccess, requestedAccess)) {
accessGranted = isAccessGranted(pathAccess, requestedAccess);
} else {
String currentPath = path;
while (currentPath.length() > 0 && !"/".equals(currentPath)) {
currentPath = SVNPathUtil.getAbsolutePath(SVNPathUtil.removeTail(currentPath));
pathAccess = checkCurrentPath(currentPath, user);
if (isAccessDetermined(pathAccess, requestedAccess)) {
accessGranted = isAccessGranted(pathAccess, requestedAccess);
break;
}
}
}
}
if (accessGranted && ((requestedAccess & SVN_ACCESS_RECURSIVE) != SVN_ACCESS_NONE)) {
accessGranted = checkTreeAccess(user, path, requestedAccess);
}
return accessGranted;
}
private int[] checkCurrentPath(String currentPath, String user) {
int[] pathAccess = new int[]{SVN_ACCESS_NONE, SVN_ACCESS_NONE};
PathAccess currentPathAccess = (PathAccess) myPathRules.get(currentPath);
if (currentPathAccess != null) {
pathAccess = currentPathAccess.checkAccess(user);
} else if (!myAnonymous) {
RepositoryAccess commonRepositoryAccess = (RepositoryAccess) getRules().get(ANONYMOUS_REPOSITORY);
if (commonRepositoryAccess != null) {
pathAccess = commonRepositoryAccess.checkPathAccess(user, currentPath);
}
}
return pathAccess;
}
private int[] checkPathAccess(String user, String path) {
int[] result = new int[]{SVN_ACCESS_NONE, SVN_ACCESS_NONE};
PathAccess pathAccess = (PathAccess) myPathRules.get(path);
if (pathAccess != null) {
result = pathAccess.checkAccess(user);
}
return result;
}
private boolean checkTreeAccess(String user, String path, int requestedAccess) {
if (myRules == null) {
return false;
}
boolean accessGranted = true;
for (Iterator iterator = myRules.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String currentPath = (String) entry.getKey();
if (SVNPathUtil.isAncestor(path, currentPath)) {
PathAccess currentPathAccess = (PathAccess) entry.getValue();
int[] pathAccess = currentPathAccess.checkAccess(user);
accessGranted = isAccessGranted(pathAccess, requestedAccess) || !isAccessDetermined(pathAccess, requestedAccess);
if (!accessGranted) {
return accessGranted;
}
}
}
return accessGranted;
}
private boolean isAccessGranted(int[] pathAccess, int requestedAccess) {
if (pathAccess == null) {
return false;
}
int allow = pathAccess[0];
int deny = pathAccess[1];
int strippedAccess = requestedAccess & (SVN_ACCESS_READ | SVN_ACCESS_WRITE);
return (deny & requestedAccess) == SVN_ACCESS_NONE || (allow & requestedAccess) == strippedAccess;
}
private boolean isAccessDetermined(int[] pathAccess, int requestedAccess) {
if (pathAccess == null) {
return false;
}
int allow = pathAccess[0];
int deny = pathAccess[1];
return ((deny & requestedAccess) != SVN_ACCESS_NONE) || ((allow & requestedAccess) != SVN_ACCESS_NONE);
}
}
private class PathAccess {
private Map myRules;
private void addRule(String matchString, String value) {
myRules = myRules == null ? new SVNHashMap() : myRules;
myRules.put(matchString, value);
}
private void validateRules() throws SVNException {
if (myRules != null) {
for (Iterator iterator = myRules.keySet().iterator(); iterator.hasNext();) {
String matchString = (String) iterator.next();
if (matchString.startsWith("@")) {
if (!getGroups().keySet().contains(matchString.substring("@".length()))) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An authz rule refers to group ''{0}'', which is undefined.", matchString), SVNLogType.NETWORK);
}
} else if (matchString.startsWith("&")) {
if (!getAliases().keySet().contains(matchString.substring("&".length()))) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_INVALID_CONFIG_VALUE, "An authz rule refers to alias ''{0}'', which is undefined.", matchString), SVNLogType.NETWORK);
}
}
}
}
}
private int[] checkAccess(String user) {
if (myRules == null) {
return null;
}
int deny = SVN_ACCESS_NONE;
int allow = SVN_ACCESS_NONE;
for (Iterator iterator = myRules.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String matchString = (String) entry.getKey();
String accessType = (String) entry.getValue();
if (ruleApliesToUser(matchString, user)) {
if (accessType.indexOf('r') >= 0) {
allow |= SVN_ACCESS_READ;
} else {
deny |= SVN_ACCESS_READ;
}
if (accessType.indexOf('w') >= 0) {
allow |= SVN_ACCESS_WRITE;
} else {
deny |= SVN_ACCESS_WRITE;
}
}
}
return new int[]{allow, deny};
}
private boolean ruleApliesToUser(String matchString, String user) {
if (matchString.startsWith("~")) {
return !ruleApliesToUser(matchString.substring("~".length()), user);
}
if (matchString.equals("*")) {
return true;
}
if (matchString.equals("$anonymous")) {
return user == null;
}
if (matchString.equals("$authenticated")) {
return user != null;
}
if (user == null) {
return false;
}
if (matchString.startsWith("@")) {
return groupContainsUser(matchString.substring("@".length()), user);
} else if (matchString.startsWith("&")) {
return aliasIsUser(matchString.substring("&".length()), user);
} else {
return matchString.equals(user);
}
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVBase64OutputStream extends OutputStream {
private static final int BASE64_LINE_LENGTH = 57;
private Writer myWriter;
private ByteArrayOutputStream myBuffer;
public DAVBase64OutputStream(Writer dst) {
myWriter = dst;
myBuffer = new ByteArrayOutputStream(100);
}
public void write(int b) throws IOException {
write(new byte[] {(byte) (b & 0xff)}, 0, 1);
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
public void close() throws IOException {
flush();
}
public void write(byte[] b, int off, int len) throws IOException {
while (len > 0) {
int needed = BASE64_LINE_LENGTH - myBuffer.size();
int toWrite = Math.min(needed, len);
myBuffer.write(b, off, toWrite);
off += toWrite;
len -= toWrite;
if (myBuffer.size() == BASE64_LINE_LENGTH) {
flushBuffer();
}
}
}
public void flush() throws IOException {
if (myBuffer.size() > 0) {
flushBuffer();
}
}
private void flushBuffer() throws IOException {
myWriter.write(SVNBase64.byteArrayToBase64(myBuffer.toByteArray()) + "\n");
myBuffer.reset();
}
}

View File

@@ -0,0 +1,139 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.dav.http.HTTPHeader;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVCheckOutHandler extends ServletDAVHandler {
private DAVCheckOutRequest myDAVRequest;
public DAVCheckOutHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
public void execute() throws SVNException {
long readLength = readInput(false);
boolean applyToVSN = false;
boolean isUnreserved = false;
boolean createActivity = false;
List activities = null;
if (readLength > 0) {
DAVCheckOutRequest davRequest = getCheckOutRequest();
if (davRequest.isApplyToVersion()) {
if (getRequestHeader(LABEL_HEADER) != null) {
response("DAV:apply-to-version cannot be used in conjunction with a Label header.",
DAVServlet.getStatusLine(HttpServletResponse.SC_CONFLICT), HttpServletResponse.SC_CONFLICT);
}
applyToVSN = true;
}
isUnreserved = davRequest.isUnreserved();
DAVElementProperty rootElement = davRequest.getRoot();
DAVElementProperty activitySetElement = rootElement.getChild(DAVCheckOutRequest.ACTIVITY_SET);
if (activitySetElement != null) {
if (activitySetElement.hasChild(DAVCheckOutRequest.NEW)) {
createActivity = true;
} else {
activities = new LinkedList();
List activitySetChildren = activitySetElement.getChildren();
for (Iterator activitySetIter = activitySetChildren.iterator(); activitySetIter.hasNext();) {
DAVElementProperty activitySetChild = (DAVElementProperty) activitySetIter.next();
if (activitySetChild.getName() == DAVElement.HREF) {
activities.add(activitySetChild.getFirstValue(true));
}
}
if (activities.isEmpty()) {
throw new DAVException("Within the DAV:activity-set element, the DAV:new element must be used, or at least one DAV:href must be specified.",
null, HttpServletResponse.SC_BAD_REQUEST, null, SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
}
}
}
DAVResource resource = getRequestedDAVResource(true, applyToVSN);
if (!resource.exists()) {
throw new DAVException(DAVServlet.getStatusLine(HttpServletResponse.SC_NOT_FOUND), null, HttpServletResponse.SC_NOT_FOUND, null,
SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
if (resource.getResourceURI().getType() != DAVResourceType.REGULAR &&
resource.getResourceURI().getType() != DAVResourceType.VERSION) {
response("Cannot checkout this type of resource.", DAVServlet.getStatusLine(HttpServletResponse.SC_CONFLICT),
HttpServletResponse.SC_CONFLICT);
}
if (!resource.isVersioned()) {
response("Cannot checkout unversioned resource.", DAVServlet.getStatusLine(HttpServletResponse.SC_CONFLICT),
HttpServletResponse.SC_CONFLICT);
}
if (resource.isWorking()) {
response("The resource is already checked out to the workspace.", DAVServlet.getStatusLine(HttpServletResponse.SC_CONFLICT),
HttpServletResponse.SC_CONFLICT);
}
DAVResource workingResource = null;
try {
workingResource = checkOut(resource, false, isUnreserved, createActivity, activities);
} catch (DAVException dave) {
throw new DAVException("Could not CHECKOUT resource {0}.", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) },
HttpServletResponse.SC_CONFLICT, null, SVNLogType.NETWORK, Level.FINE, dave, null, null, 0, null);
}
setResponseHeader(CACHE_CONTROL_HEADER, CACHE_CONTROL_VALUE);
if (workingResource == null) {
setResponseHeader(HTTPHeader.CONTENT_LENGTH_HEADER, "0");
return;
}
handleDAVCreated(workingResource.getResourceURI().getRequestURI(), "Checked-out resource", false);
}
protected DAVRequest getDAVRequest() {
return getCheckOutRequest();
}
private DAVCheckOutRequest getCheckOutRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVCheckOutRequest();
}
return myDAVRequest;
}
}

View File

@@ -0,0 +1,70 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVCheckOutRequest extends DAVRequest {
public static final DAVElement NEW = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "new");
public static final DAVElement CHECKOUT = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "checkout");
public static final DAVElement APPLY_TO_VERSION = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "apply-to-version");
public static final DAVElement UNRESERVED = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "unreserved");
public static final DAVElement FORK_OK = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "fork-ok");
public static final DAVElement ACTIVITY_SET = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "activity-set");
public boolean isUnreserved() throws SVNException {
DAVElementProperty root = getRoot();
return root.hasChild(UNRESERVED);
}
public boolean isForkOk() throws SVNException {
DAVElementProperty root = getRoot();
return root.hasChild(FORK_OK);
}
public boolean isApplyToVersion() throws SVNException {
DAVElementProperty root = getRoot();
return root.hasChild(APPLY_TO_VERSION);
}
public DAVElementProperty getRoot() throws SVNException {
if (getRootElement() == null) {
invalidXMLRoot();
}
return getRootElement();
}
protected void init() throws SVNException {
DAVElementProperty rootElement = getRootElement();
if (rootElement == null || rootElement.getName() != CHECKOUT) {
invalidXMLRoot();
}
}
protected void invalidXMLRoot() throws SVNException {
throw new DAVException("The request body, if present, must be a DAV:checkout element.", null, HttpServletResponse.SC_BAD_REQUEST,
null, SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
}

View File

@@ -0,0 +1,304 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.net.URI;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.http.HTTPHeader;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceState;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import org.tmatesoft.svn.core.internal.server.dav.DAVServletUtil;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVCopyMoveHandler extends ServletDAVHandler {
private boolean myIsMove;
protected DAVCopyMoveHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response, boolean isMove) {
super(connector, request, response);
myIsMove = isMove;
}
public void execute() throws SVNException {
DAVResource resource = getRequestedDAVResource(!myIsMove, false);
if (!resource.exists()) {
sendError(HttpServletResponse.SC_NOT_FOUND, null);
return;
}
if (resource.getType() != DAVResourceType.REGULAR) {
String body = "Cannot COPY/MOVE resource " + SVNEncodingUtil.xmlEncodeCDATA(getURI()) + ".";
response(body, DAVServlet.getStatusLine(HttpServletResponse.SC_METHOD_NOT_ALLOWED), HttpServletResponse.SC_METHOD_NOT_ALLOWED);
return;
}
String destination = getRequestHeader(HTTPHeader.DESTINATION_HEADER);
if (destination == null) {
String netScapeHost = getRequestHeader(HTTPHeader.HOST_HEADER);
String netScapeNewURI = getRequestHeader(HTTPHeader.NEW_URI_HEADER);
if (netScapeHost != null && netScapeNewURI != null) {
String path = SVNPathUtil.append(netScapeHost, netScapeNewURI);
if (path.startsWith("/")) {
path = path.substring(1);
}
destination = "http://" + path;
}
}
if (destination == null) {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, "The request is missing a Destination header.");
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
URI uri = null;
try {
uri = DAVServletUtil.lookUpURI(destination, getRequest(), true);
} catch (DAVException dave) {
if (dave.getResponseCode() == HttpServletResponse.SC_BAD_REQUEST) {
throw dave;
}
response(dave.getMessage(), DAVServlet.getStatusLine(dave.getResponseCode()), dave.getResponseCode());
}
String path = uri.getPath();
DAVRepositoryManager manager = getRepositoryManager();
String resourceContext = manager.getResourceContext();
if (!path.startsWith(resourceContext)) {
throw new DAVException("Destination url starts with a wrong context", HttpServletResponse.SC_BAD_REQUEST, 0);
}
path = path.substring(resourceContext.length());
DAVResource newResource = getRequestedDAVResource(false, false, path);
int overwrite = getOverwrite();
if (overwrite < 0) {
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
if (newResource.exists() && overwrite == 0) {
response("Destination is not empty and Overwrite is not \"T\"", DAVServlet.getStatusLine(HttpServletResponse.SC_PRECONDITION_FAILED),
HttpServletResponse.SC_PRECONDITION_FAILED);
return;
}
if (resource.equals(newResource)) {
response("Source and Destination URIs are the same.", DAVServlet.getStatusLine(HttpServletResponse.SC_FORBIDDEN),
HttpServletResponse.SC_FORBIDDEN);
return;
}
boolean isDir = resource.isCollection();
DAVDepth depth = null;
try {
depth = getRequestDepth(DAVDepth.DEPTH_INFINITY);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_BAD_REQUEST, null, null);
}
if (depth == DAVDepth.DEPTH_ONE) {
//add logging here later
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
if (myIsMove && isDir && depth != DAVDepth.DEPTH_INFINITY) {
//add logging here later
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
if (myIsMove) {
try {
validateRequest(resource, depth, DAV_VALIDATE_PARENT | DAV_VALIDATE_USE_424, null, null, null);
} catch (DAVException dave) {
throw new DAVException("Could not MOVE {0} due to a failed precondition on the source (e.g. locks).",
new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) }, dave.getResponseCode(), null, SVNLogType.NETWORK,
Level.FINE, dave, null, null, 0, dave.getResponse());
}
}
try {
validateRequest(newResource, DAVDepth.DEPTH_INFINITY, DAV_VALIDATE_PARENT | DAV_VALIDATE_USE_424, null, null, null);
} catch (DAVException dave) {
throw new DAVException("Could not MOVE/COPY {0} due to a failed precondition on the destination (e.g. locks).",
new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) }, dave.getResponseCode(), null, SVNLogType.NETWORK, Level.FINE,
dave, null, null, 0, dave.getResponse());
}
if (isDir && depth == DAVDepth.DEPTH_INFINITY && resource.isParentResource(newResource)) {
response("Source collection contains the Destination.", DAVServlet.getStatusLine(HttpServletResponse.SC_FORBIDDEN), HttpServletResponse.SC_FORBIDDEN);
return;
}
if (isDir && newResource.isParentResource(newResource)) {
response("Destination collection contains the Source and Overwrite has been specified.", DAVServlet.getStatusLine(HttpServletResponse.SC_FORBIDDEN),
HttpServletResponse.SC_FORBIDDEN);
return;
}
readInput(true);
DAVLockInfoProvider lockProvider = null;
try {
lockProvider = DAVLockInfoProvider.createLockInfoProvider(this, false);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, null);
}
if (myIsMove) {
unlock(resource, null);
}
DAVAutoVersionInfo srcAVInfo = null;
if (myIsMove) {
srcAVInfo = autoCheckOut(resource, true);
}
boolean replaceDestination = false;
DAVResourceState resNewState = getResourceState(newResource);
if (newResource.exists()) {
if (myIsMove || !newResource.isVersioned()) {
replaceDestination = true;
} else if (resource.getType() != newResource.getType()) {
replaceDestination = true;
} else if (resource.isCollection() != newResource.isCollection()) {
replaceDestination = true;
}
}
DAVAutoVersionInfo dstAVInfo = null;
if (!newResource.exists() || replaceDestination) {
try {
dstAVInfo = autoCheckOut(newResource, true);
} catch (DAVException dave) {
if (myIsMove) {
autoCheckIn(null, true, false, srcAVInfo);
}
throw dave;
}
}
if (srcAVInfo != null && srcAVInfo.getParentResource() != null && dstAVInfo != null &&
dstAVInfo.getParentResource() != null) {
DAVResource srcParentResource = srcAVInfo.getParentResource();
DAVResource dstParentResource = dstAVInfo.getParentResource();
if (srcParentResource.equals(dstParentResource)) {
dstAVInfo.setParentResource(srcAVInfo.getParentResource());
}
}
DAVException err1 = null;
if (replaceDestination) {
try {
removeResource(newResource);
} catch (DAVException dave) {
err1 = dave;
}
}
if (err1 == null) {
if (myIsMove) {
try {
moveResource(resource, newResource);
} catch (DAVException dave) {
err1 = dave;
}
} else {
try {
copyResource(resource, newResource);
} catch (DAVException dave) {
err1 = dave;
}
}
}
DAVException err2 = null;
try {
autoCheckIn(null, err1 != null, false, dstAVInfo);
} catch (DAVException dave) {
err2 = dave;
}
DAVException err3 = null;
if (myIsMove) {
try {
autoCheckIn(null, err1 != null, false, srcAVInfo);
} catch (DAVException dave) {
err3 = dave;
}
}
if (err1 != null) {
throw new DAVException("Could not MOVE/COPY {0}.", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) },
err1.getResponseCode(), err1, 0);
}
if (err2 != null) {
//throw new DAVException("The MOVE/COPY was successful, but there was a problem automatically checking in the source parent collection.", null, err2.getResponseCode(), err2, 0);
//TODO: add logging here later
}
if (err3 != null) {
//TODO: add logging here later
}
try {
notifyCreated(newResource, lockProvider, resNewState, depth);
} catch (DAVException dave) {
throw new DAVException("The MOVE/COPY was successful, but there was a problem updating the lock information.", null,
dave.getResponseCode(), dave, 0);
}
handleDAVCreated(uri.toString(), "Destination", resNewState == DAVResourceState.EXISTS);
}
protected int getOverwrite() {
String overwriteValue = getRequestHeader(HTTPHeader.OVERWRITE_HEADER);
if (overwriteValue == null) {
return 1;
}
overwriteValue = overwriteValue.toLowerCase();
if (overwriteValue.length() == 1 && overwriteValue.charAt(0) == 'f') {
return 0;
}
if (overwriteValue.length() == 1 && overwriteValue.charAt(0) == 't') {
return 1;
}
//TODO: add logging here later
return -1;
}
protected DAVRequest getDAVRequest() {
return null;
}
}

View File

@@ -0,0 +1,73 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVDatedRevisionHandler extends DAVReportHandler {
private DAVDatedRevisionRequest myDAVRequest;
public DAVDatedRevisionHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
protected DAVRequest getDAVRequest() {
return getDatedRevisionRequest();
}
private DAVDatedRevisionRequest getDatedRevisionRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVDatedRevisionRequest();
}
return myDAVRequest;
}
public void execute() throws SVNException {
setDAVResource(getRequestedDAVResource(false, false));
String responseBody = generateResponseBody();
try {
int contentLength = responseBody.getBytes(UTF8_ENCODING).length;
setResponseContentLength(contentLength);
} catch (UnsupportedEncodingException e) {
}
write(responseBody);
}
private String generateResponseBody() throws SVNException {
StringBuffer xmlBuffer = new StringBuffer();
long revision = getDatedRevision();
addXMLHeader(xmlBuffer, null);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_NAME.getName(), String.valueOf(revision), xmlBuffer);
addXMLFooter(xmlBuffer, null);
return xmlBuffer.toString();
}
private long getDatedRevision() throws SVNException {
return getDAVResource().getRepository().getDatedRevision(getDatedRevisionRequest().getDate());
}
}

View File

@@ -0,0 +1,41 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Date;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.util.SVNDate;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVDatedRevisionRequest extends DAVRequest {
Date myDate = null;
public Date getDate() {
return myDate;
}
private void setDate(Date date) {
myDate = date;
}
protected void init() throws SVNException {
DAVElementProperty creationDateElement = getRootElement().getChild(DAVElement.CREATION_DATE);
String dateString = creationDateElement.getFirstValue(true);
setDate(SVNDate.parseDate(dateString));
}
}

View File

@@ -0,0 +1,102 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVDeleteHandler extends ServletDAVHandler {
private DAVDeleteRequest myDAVRequest;
public DAVDeleteHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
public void execute() throws SVNException {
readInput(false);
DAVResource resource = getRequestedDAVResource(false, false);
if (!resource.exists()) {
sendError(HttpServletResponse.SC_NOT_FOUND, null);
return;
}
DAVDepth depth = getRequestDepth(DAVDepth.DEPTH_INFINITY);
if (resource.isCollection() && depth != DAVDepth.DEPTH_INFINITY) {
SVNDebugLog.getDefaultLog().logError(SVNLogType.NETWORK, "Depth must be \"infinity\" for DELETE of a collection.");
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
if (!resource.isCollection() && depth == DAVDepth.DEPTH_ONE) {
SVNDebugLog.getDefaultLog().logError(SVNLogType.NETWORK, "Depth of \"1\" is not allowed for DELETE.");
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
try {
validateRequest(resource, depth, DAV_VALIDATE_PARENT | DAV_VALIDATE_USE_424, null, null, null);
} catch (DAVException dave) {
throw new DAVException("Could not DELETE {0} due to a failed precondition (e.g. locks).",
new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) }, dave.getResponseCode(), null, SVNLogType.NETWORK, Level.FINE,
dave, null, null, 0, dave.getResponse());
}
int respCode = unlock(resource, null);
if (respCode != HttpServletResponse.SC_OK) {
sendError(respCode, null);
return;
}
DAVAutoVersionInfo avInfo = autoCheckOut(resource, true);
try {
removeResource(resource);
} catch (DAVException dave) {
autoCheckIn(null, true, false, avInfo);
throw new DAVException("Could not DELETE {0}.", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) }, dave.getResponseCode(),
dave, 0);
}
try {
autoCheckIn(null, false, false, avInfo);
} catch (DAVException dave) {
//TODO: add better logging here later
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, "The DELETE was successful, but there was a problem automatically checking in the parent collection.");
}
setResponseStatus(HttpServletResponse.SC_NO_CONTENT);
}
protected DAVRequest getDAVRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVDeleteRequest();
}
return myDAVRequest;
}
}

View File

@@ -0,0 +1,26 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import org.tmatesoft.svn.core.SVNException;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVDeleteRequest extends DAVRequest {
protected void init() throws SVNException {
}
}

View File

@@ -0,0 +1,151 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVElementProperty {
private ArrayList myValues;
private Map myAttributes;
private List myChildren;
private DAVElement myElementName;
private DAVElementProperty myParent;
private LivePropertySpecification myLivePropertySpec;
public DAVElementProperty(DAVElement elementName, DAVElementProperty parent) {
myElementName = elementName;
myParent = parent;
}
public DAVElementProperty getParent() {
return myParent;
}
public DAVElement getName() {
return myElementName;
}
public void setElementName(DAVElement element) {
myElementName = element;
}
public boolean hasChild(DAVElement element) {
return getChild(element) != null;
}
public DAVElementProperty getChild(DAVElement element) {
if (myChildren != null) {
for (Iterator childrenIter = myChildren.iterator(); childrenIter.hasNext();) {
DAVElementProperty nextChild = (DAVElementProperty) childrenIter.next();
if (element == nextChild.getName()) {
return nextChild;
}
}
}
return null;
}
public Map getAttributes() {
return myAttributes;
}
public void addValue(String cdata) throws SVNException {
if (myChildren != null) {
invalidXML();
} else if (myValues == null) {
myValues = new ArrayList();
}
myValues.add(cdata);
}
public String getFirstValue(boolean trim) {
if (myValues != null) {
String value = (String) myValues.get(0);
if (trim && value != null) {
value = value.trim();
}
return value;
}
return null;
}
public Collection getValues() {
return myValues;
}
public String getAttributeValue(String name) {
if (myAttributes != null) {
return (String) myAttributes.get(name);
}
return null;
}
public void setAttributes(Attributes attributes) {
myAttributes = getAttributesMap(attributes);
}
public List getChildren() {
return myChildren;
}
public boolean isEmpty() {
return (myChildren == null || myChildren.isEmpty()) && (myValues == null || myValues.isEmpty());
}
protected DAVElementProperty addChild(DAVElement element, Attributes attrs) throws SVNException {
if (myValues != null) {
invalidXML();
} else if (myChildren == null) {
myChildren = new LinkedList();
}
DAVElementProperty child = new DAVElementProperty(element, this);
myChildren.add(child);
child.setAttributes(attrs);
return child;
}
private Map getAttributesMap(Attributes attrs) {
Map attributes = null;
if (attrs.getLength() != 0) {
attributes = new SVNHashMap();
for (int i = 0; i < attrs.getLength(); i++) {
attributes.put(attrs.getLocalName(i), attrs.getValue(i));
}
}
return attributes;
}
private void invalidXML() throws SVNException {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.XML_MALFORMED, "Malformed XML"), SVNLogType.NETWORK);
}
}

View File

@@ -0,0 +1,154 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.ISVNFileRevisionHandler;
import org.tmatesoft.svn.core.io.SVNFileRevision;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVFileRevisionsHandler extends DAVReportHandler implements ISVNFileRevisionHandler {
private static final String FILE_REVISION_TAG = "file-rev";
private static final String REVISION_PROPERTY_TAG = "rev-prop";
private static final String SET_PROPERTY_TAG = "set-prop";
private static final String REMOVE_PROPERTY_TAG = "remove-prop";
private static final String MERGED_REVISION_TAG = "merged-revision";
private DAVFileRevisionsRequest myDAVRequest;
private boolean myWriteHeader;
private DAVReportHandler myCommonReportHandler;
public DAVFileRevisionsHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
myCommonReportHandler = commonReportHandler;
}
protected DAVRequest getDAVRequest() {
return getFileRevsionsRequest();
}
private DAVFileRevisionsRequest getFileRevsionsRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVFileRevisionsRequest();
}
return myDAVRequest;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace(null);
setDAVResource(getRequestedDAVResource(false, false));
myWriteHeader = true;
String path = SVNPathUtil.append(getDAVResource().getResourceURI().getPath(), getFileRevsionsRequest().getPath());
try {
getDAVResource().getRepository().getFileRevisions(path, getFileRevsionsRequest().getStartRevision(),
getFileRevsionsRequest().getEndRevision(), getFileRevsionsRequest().isIncludeMergedRevisions(), this);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
svne.getErrorMessage().getMessage(), null);
}
try {
maybeSendHeader();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error beginning REPORT reponse", null);
}
try {
writeXMLFooter(null);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error ending REPORT reponse", null);
}
}
public void openRevision(SVNFileRevision fileRevision) throws SVNException {
maybeSendHeader();
Map attrs = new SVNHashMap();
attrs.put(PATH_ATTR, fileRevision.getPath());
attrs.put(REVISION_ATTR, String.valueOf(fileRevision.getRevision()));
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, FILE_REVISION_TAG, SVNXMLUtil.XML_STYLE_NORMAL,
attrs, null);
write(xmlBuffer);
for (Iterator iterator = fileRevision.getRevisionProperties().nameSet().iterator(); iterator.hasNext();) {
String propertyName = (String) iterator.next();
writePropertyTag(REVISION_PROPERTY_TAG, propertyName, fileRevision.getRevisionProperties().getSVNPropertyValue(propertyName));
}
for (Iterator iterator = fileRevision.getPropertiesDelta().nameSet().iterator(); iterator.hasNext();) {
String propertyName = (String) iterator.next();
SVNPropertyValue propertyValue = fileRevision.getPropertiesDelta().getSVNPropertyValue(propertyName);
if (propertyValue != null) {
writePropertyTag(SET_PROPERTY_TAG, propertyName, propertyValue);
} else {
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, REMOVE_PROPERTY_TAG, SVNXMLUtil.XML_STYLE_SELF_CLOSING, "name", propertyName, null);
write(xmlBuffer);
}
}
if (fileRevision.isResultOfMerge()) {
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, MERGED_REVISION_TAG, SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, null);
write(xmlBuffer);
}
}
public void closeRevision(String token) throws SVNException {
StringBuffer xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, FILE_REVISION_TAG, null);
write(xmlBuffer);
}
public void applyTextDelta(String path, String baseChecksum) throws SVNException {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, TXDELTA_ATTR, SVNXMLUtil.XML_STYLE_NORMAL, null, null);
write(xmlBuffer);
}
public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
writeTextDeltaChunk(diffWindow);
return null;
}
public void textDeltaEnd(String path) throws SVNException {
textDeltaChunkEnd();
setWriteTextDeltaHeader(true);
StringBuffer xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, TXDELTA_ATTR, null);
write(xmlBuffer);
}
private void maybeSendHeader() throws SVNException {
if (myWriteHeader) {
writeXMLHeader(null);
myWriteHeader = false;
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVFileRevisionsRequest extends DAVRequest {
private String myPath;
private long myStartRevision = DAVResource.INVALID_REVISION;
private long myEndRevision = DAVResource.INVALID_REVISION;
private boolean myIsIncludeMergedRevisions;
public String getPath() {
return myPath;
}
public long getStartRevision() {
return myStartRevision;
}
public long getEndRevision() {
return myEndRevision;
}
public boolean isIncludeMergedRevisions() {
return myIsIncludeMergedRevisions;
}
protected void init() throws SVNException {
DAVElementProperty rootElement = getRootElement();
List children = rootElement.getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) iterator.next();
DAVElement childElementName = childElement.getName();
if (!DAVElement.SVN_NAMESPACE.equals(childElementName.getNamespace())) {
continue;
}
if (childElementName == DAVElement.PATH) {
String path = childElement.getFirstValue(false);
DAVPathUtil.testCanonical(path);
myPath = path;
} else if (childElementName == DAVElement.START_REVISION) {
try {
myStartRevision = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (childElementName == DAVElement.END_REVISION) {
try {
myEndRevision = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (childElementName == DAVElement.INCLUDE_MERGED_REVISIONS) {
myIsIncludeMergedRevisions = true;
}
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceURI;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVGetDeletedRevisionHandler extends DAVReportHandler {
private DAVGetDeletedRevisionRequest myDAVRequest;
private DAVReportHandler myCommonReportHandler;
protected DAVGetDeletedRevisionHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(connector, request, response);
myCommonReportHandler = commonReportHandler;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace(null);
setDAVResource(getRequestedDAVResource(false, false));
DAVGetDeletedRevisionRequest request = getDeletedRevisionRequest();
String relPath = request.getPath();
long pegRev = request.getPegRevision();
long endRev = request.getEndRevision();
if (relPath == null || !SVNRevision.isValidRevisionNumber(pegRev) || !SVNRevision.isValidRevisionNumber(endRev)) {
throw new DAVException("Not all parameters passed.", null, HttpServletResponse.SC_BAD_REQUEST, null, SVNLogType.NETWORK, Level.FINE,
null, DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE, 0, null);
}
DAVResourceURI resourceURI = getDAVResource().getResourceURI();
String path = relPath;
if (!path.startsWith("/")) {
path = SVNPathUtil.append(resourceURI.getPath(), relPath);
}
SVNRepository repository = getDAVResource().getRepository();
long deletedRev = SVNRepository.INVALID_REVISION;
try {
deletedRev = repository.getDeletedRevision(path, pegRev, endRev);
} catch (SVNException svne) {
throw new DAVException("Could not find revision path was deleted.", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
writeXMLHeader(null);
StringBuffer xmlBuffer = SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_NAME.getName(), String.valueOf(deletedRev), null);
write(xmlBuffer);
writeXMLFooter(null);
}
protected DAVRequest getDAVRequest() {
return getDeletedRevisionRequest();
}
private DAVGetDeletedRevisionRequest getDeletedRevisionRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVGetDeletedRevisionRequest();
}
return myDAVRequest;
}
}

View File

@@ -0,0 +1,78 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVGetDeletedRevisionRequest extends DAVRequest {
private long myPegRevision;
private long myEndRevision;
private String myPath;
public long getPegRevision() {
return myPegRevision;
}
public long getEndRevision() {
return myEndRevision;
}
public String getPath() {
return myPath;
}
protected void init() throws SVNException {
DAVElementProperty rootElement = getRootElement();
List rootChildren = rootElement.getChildren();
if (rootChildren != null) {
for (Iterator childrenIter = rootChildren.iterator(); childrenIter.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) childrenIter.next();
DAVElement childElementName = childElement.getName();
if (!DAVElement.SVN_NAMESPACE.equals(childElementName.getNamespace())) {
continue;
}
if (childElementName == DAVElement.PEG_REVISION) {
try {
myPegRevision = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (childElementName == DAVElement.END_REVISION) {
try {
myEndRevision = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (childElementName == DAVElement.PATH) {
String path = childElement.getFirstValue(false);
DAVPathUtil.testCanonical(path);
myPath = path;
}
}
}
}
}

View File

@@ -0,0 +1,203 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
import org.tmatesoft.svn.util.Version;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVGetHandler extends ServletDAVHandler {
public DAVGetHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
public void execute() throws SVNException {
DAVResource resource = getRequestedDAVResource(true, false);
if (!resource.exists()) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_PATH_NOT_FOUND, "Path ''{0}'' you requested not found", resource.getResourceURI().getPath()), SVNLogType.NETWORK);
}
if (resource.getResourceURI().getType() != DAVResourceType.REGULAR && resource.getResourceURI().getType() != DAVResourceType.VERSION
&& resource.getResourceURI().getType() != DAVResourceType.WORKING) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_MALFORMED_DATA, "Cannot GET this type of resource."), SVNLogType.NETWORK);
}
setDefaultResponseHeaders();
setResponseHeaders(resource);
try {
checkPreconditions(resource.getETag(), resource.getLastModified());
} catch (SVNException e) {
//Nothing to do, there are no enough conditions
}
if (resource.isCollection()) {
StringBuffer body = new StringBuffer();
generateResponseBody(resource, body);
String responseBody = body.toString();
try {
setResponseContentLength(responseBody.getBytes(UTF8_ENCODING).length);
} catch (UnsupportedEncodingException e) {
setResponseContentLength(responseBody.getBytes().length);
}
try {
getResponseWriter().write(responseBody);
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, e), e, SVNLogType.NETWORK);
}
} else if (resource.getDeltaBase() != null) {
//Here we should send SVN delta (for old clients)
} else {
resource.writeTo(getResponseOutputStream());
}
}
protected DAVRequest getDAVRequest() {
return null;
}
protected int checkPreconditions(String eTag, Date lastModified) {
super.checkPreconditions(eTag, lastModified);
lastModified = lastModified == null ? new Date() : lastModified;
boolean isNotModified = false;
Enumeration ifNoneMatch = getRequestHeaders(IF_NONE_MATCH_HEADER);
if (ifNoneMatch != null && ifNoneMatch.hasMoreElements()) {
if (eTag != null) {
if (getRequestHeaders(RANGE_HEADER) != null && getRequestHeaders(RANGE_HEADER).hasMoreElements()) {
isNotModified = !eTag.startsWith("W") && containsValue(ifNoneMatch, eTag, "*");
} else {
isNotModified = containsValue(ifNoneMatch, eTag, "*");
}
}
}
long ifModified = getRequestDateHeader(IF_MODIFIED_SINCE_HEADER);
long date = getRequestDateHeader(DATE_HEADER);
if ((isNotModified || ifNoneMatch == null || !ifNoneMatch.hasMoreElements()) && ifModified != -1 && date != -1) {
isNotModified = ifModified >= lastModified.getTime() && ifModified <= date;
}
if (isNotModified) {
// TODO status HTTP_NOT_MODIFIED
} else {
//TODO status OK
}
return 0;//TODO
}
private void setResponseHeaders(DAVResource resource) {
try {
setResponseContentType(resource.getContentType());
} catch (SVNException e) {
//nothing to do we just skip this header
}
setResponseHeader(ACCEPT_RANGES_HEADER, ACCEPT_RANGES_DEFAULT_VALUE);
try {
Date lastModifiedTime = resource.getLastModified();
if (lastModifiedTime != null) {
setResponseHeader(LAST_MODIFIED_HEADER, SVNDate.formatRFC1123Date(lastModifiedTime));
}
} catch (SVNException e) {
//nothing to do we just skip this header
}
String eTag = resource.getETag();
if (eTag != null) {
setResponseHeader(ETAG_HEADER, eTag);
}
}
private void generateResponseBody(DAVResource resource, StringBuffer buffer) throws SVNException {
startBody(SVNPathUtil.tail(resource.getResourceURI().getContext()), resource.getResourceURI().getPath(), resource.getRevision(), buffer);
addUpperDirectoryLink(resource.getResourceURI().getContext(), resource.getResourceURI().getPath(), buffer);
addDirectoryEntries(resource, buffer);
finishBody(buffer);
}
private void startBody(String contextComponent, String path, long revision, StringBuffer buffer) {
buffer.append("<html><head><title>");
buffer.append(contextComponent);
buffer.append(" - Revision ");
buffer.append(String.valueOf(revision));
buffer.append(": ");
buffer.append(path);
buffer.append("</title></head>\n");
buffer.append("<body>\n<h2>");
buffer.append(contextComponent);
buffer.append(" - Revision ");
buffer.append(String.valueOf(revision));
buffer.append(": ");
buffer.append(path);
buffer.append("</h2>\n <ul>\n");
}
private void addUpperDirectoryLink(String context, String path, StringBuffer buffer) {
if (!"/".equals(path)) {
buffer.append("<li><a href=\"");
buffer.append(context);
String parent = DAVPathUtil.removeTail(path, true);
buffer.append("/".equals(parent) ? "" : parent);
buffer.append("/");
buffer.append("\">..</a></li>\n");
}
}
private void addDirectoryEntries(DAVResource resource, StringBuffer buffer) throws SVNException {
for (Iterator iterator = resource.getEntries().iterator(); iterator.hasNext();) {
SVNDirEntry entry = (SVNDirEntry) iterator.next();
boolean isDir = entry.getKind() == SVNNodeKind.DIR;
buffer.append("<li><a href=\"");
buffer.append(resource.getResourceURI().getContext());
buffer.append("/".equals(resource.getResourceURI().getPath()) ? "" : resource.getResourceURI().getPath());
buffer.append(DAVPathUtil.standardize(entry.getName()));
buffer.append(isDir ? "/" : "");
buffer.append("\">");
buffer.append(entry.getName());
buffer.append(isDir ? "/" : "");
buffer.append("</a></li>\n");
}
}
private void finishBody(StringBuffer buffer) {
buffer.append("</ul><hr noshade><em>");
buffer.append("Powered by ");
buffer.append(Version.getVersionString());
buffer.append("</em>\n</body></html>");
}
}

View File

@@ -0,0 +1,180 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSLocationsFinder;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.ISVNLocationSegmentHandler;
import org.tmatesoft.svn.core.io.SVNLocationSegment;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVGetLocationSegmentsHandler extends DAVReportHandler implements ISVNLocationSegmentHandler {
private static final String GET_LOCATION_SEGMENTS_REPORT = "get-location-segments-report";
private static final String LOCATION_SEGMENT_TAG = "location-segment";
private static final String RANGE_START_ATTR = "range-start";
private static final String RANGE_END_ATTR = "range-end";
private DAVGetLocationSegmentsRequest myDAVRequest;
private boolean myIsOpenerSent;
private DAVReportHandler myCommonReportHandler;
protected DAVGetLocationSegmentsHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
myCommonReportHandler = commonReportHandler;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace(null);
DAVResource resource = getRequestedDAVResource(false, false);
setDAVResource(resource);
DAVGetLocationSegmentsRequest request = getLocationSegmentsRequest();
String path = null;
long startRev = -1;
long endRev = -1;
long pegRev = -1;
DAVElementProperty rootElement = request.getRootElement();
List children = rootElement.getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) iterator.next();
DAVElement childElementName = childElement.getName();
if (!DAVElement.SVN_NAMESPACE.equals(childElementName.getNamespace())) {
continue;
}
if (childElementName == DAVElement.PATH) {
path = childElement.getFirstValue(false);
DAVPathUtil.testCanonical(path);
String resourcePath = resource.getResourceURI().getPath();
path = SVNPathUtil.append(resourcePath, path);
} else if (childElementName == DAVElement.START_REVISION) {
try {
startRev = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (childElementName == DAVElement.END_REVISION) {
try {
endRev = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (childElementName == DAVElement.PEG_REVISION) {
try {
pegRev = Long.parseLong(childElement.getFirstValue(true));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
}
}
if (path == null) {
throw new DAVException("Not all parameters passed.", HttpServletResponse.SC_BAD_REQUEST, SVNLogType.NETWORK, DAVXMLUtil.SVN_DAV_ERROR_TAG,
DAVElement.SVN_DAV_ERROR_NAMESPACE);
}
if (SVNRevision.isValidRevisionNumber(startRev) && SVNRevision.isValidRevisionNumber(endRev) &&
endRev > startRev) {
throw new DAVException("End revision must not be younger than start revision", HttpServletResponse.SC_BAD_REQUEST, SVNLogType.NETWORK,
DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE);
}
if (SVNRevision.isValidRevisionNumber(pegRev) && SVNRevision.isValidRevisionNumber(startRev) &&
startRev > pegRev) {
throw new DAVException("Start revision must not be younger than peg revision", HttpServletResponse.SC_BAD_REQUEST, SVNLogType.NETWORK,
DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE);
}
FSLocationsFinder locationsFinder = new FSLocationsFinder(getDAVResource().getFSFS());
locationsFinder.getNodeLocationSegments(path, pegRev, startRev, endRev, this);
try {
maybeSendOpener();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error beginning REPORT reponse", null);
}
try {
writeXMLFooter(GET_LOCATION_SEGMENTS_REPORT);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error ending REPORT reponse", null);
}
}
public void handleLocationSegment(SVNLocationSegment locationSegment) throws SVNException {
maybeSendOpener();
Map attrs = new HashMap();
String path = locationSegment.getPath();
if (path != null) {
String quotedPath = SVNEncodingUtil.xmlEncodeCDATA(path, true);
attrs.put(PATH_ATTR, quotedPath);
attrs.put(RANGE_START_ATTR, String.valueOf(locationSegment.getStartRevision()));
attrs.put(RANGE_END_ATTR, String.valueOf(locationSegment.getEndRevision()));
} else {
attrs.put(RANGE_START_ATTR, String.valueOf(locationSegment.getStartRevision()));
attrs.put(RANGE_END_ATTR, String.valueOf(locationSegment.getEndRevision()));
}
StringBuffer buffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, LOCATION_SEGMENT_TAG, SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, null);
write(buffer);
}
protected DAVRequest getDAVRequest() {
return getLocationSegmentsRequest();
}
private DAVGetLocationSegmentsRequest getLocationSegmentsRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVGetLocationSegmentsRequest();
}
return myDAVRequest;
}
private void maybeSendOpener() throws SVNException {
if (!myIsOpenerSent) {
writeXMLHeader(GET_LOCATION_SEGMENTS_REPORT);
myIsOpenerSent = true;
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import org.tmatesoft.svn.core.SVNException;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVGetLocationSegmentsRequest extends DAVRequest {
public DAVGetLocationSegmentsRequest() {
}
protected void init() throws SVNException {
}
protected DAVElementProperty getRoot() {
return getRootElement();
}
}

View File

@@ -0,0 +1,99 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.SVNLocationEntry;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVGetLocationsHandler extends DAVReportHandler {
private static final String GET_LOCATIONS_REPORT = "get-locations-report";
private DAVGetLocationsRequest myDAVRequest;
private DAVReportHandler myCommonReportHandler;
public DAVGetLocationsHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
myCommonReportHandler = commonReportHandler;
}
protected DAVRequest getDAVRequest() {
return getGetLocationsRequest();
}
private DAVGetLocationsRequest getGetLocationsRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVGetLocationsRequest();
}
return myDAVRequest;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace(null);
setDAVResource(getRequestedDAVResource(false, false));
DAVResource resource = getDAVResource();
DAVGetLocationsRequest request = getGetLocationsRequest();
String path = request.getPath();
long pegRevision = request.getPegRevision();
if (path == null || !SVNRevision.isValidRevisionNumber(pegRevision)) {
throw new DAVException("Not all parameters passed.", HttpServletResponse.SC_BAD_REQUEST, SVNLogType.NETWORK,
DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE);
}
if (!path.startsWith("/")) {
path = SVNPathUtil.append(resource.getResourceURI().getPath(), path);
}
SVNRepository repository = resource.getRepository();
Collection locations = repository.getLocations(path, (Collection)null, pegRevision, request.getRevisions());
Map attrs = new SVNHashMap();
writeXMLHeader(GET_LOCATIONS_REPORT);
for (Iterator locationsIter = locations.iterator(); locationsIter.hasNext();) {
SVNLocationEntry locationEntry = (SVNLocationEntry) locationsIter.next();
attrs.clear();
attrs.put(PATH_ATTR, locationEntry.getPath());
attrs.put(REVISION_ATTR, String.valueOf(locationEntry.getRevision()));
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "location", SVNXMLUtil.XML_STYLE_SELF_CLOSING,
attrs, null);
write(xmlBuffer);
}
writeXMLFooter(GET_LOCATIONS_REPORT);
}
}

View File

@@ -0,0 +1,117 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVGetLocationsRequest extends DAVRequest {
private static final DAVElement GET_LOCATIONS_REPORT = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "get-locations-report");
private static final DAVElement PEG_REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "peg-revision");
private static final DAVElement LOCATION_REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "location-revision");
private String myPath = null;
private long myPegRevision = DAVResource.INVALID_REVISION;
private Collection myRevisions;
private long[] myRevisionsArray;
public String getPath() {
return myPath;
}
private void setPath(String path) {
myPath = path;
}
public long getPegRevision() {
return myPegRevision;
}
private void setPegRevision(long pegRevision) {
myPegRevision = pegRevision;
}
public long[] getRevisions() {
if (myRevisionsArray != null) {
return myRevisionsArray;
}
if (myRevisions != null) {
myRevisionsArray = new long[myRevisions.size()];
int i = 0;
for (Iterator revObjectsIter = myRevisions.iterator(); revObjectsIter.hasNext(); i++) {
Long revisionObject = (Long) revObjectsIter.next();
myRevisionsArray[i] = revisionObject.longValue();
}
myRevisions = null;
return myRevisionsArray;
}
return null;
}
private void addRevision(long revision) {
if (myRevisions == null) {
myRevisions = new LinkedList();
}
myRevisions.add(new Long(revision));
}
protected void init() throws SVNException {
getRootElement().setElementName(GET_LOCATIONS_REPORT);
List children = getRootElement().getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
DAVElementProperty property = (DAVElementProperty) iterator.next();
DAVElement element = property.getName();
if (element == DAVElement.PATH) {
String path = property.getFirstValue(false);
DAVPathUtil.testCanonical(path);
setPath(path);
} else if (element == PEG_REVISION) {
String pegRevisionString = property.getFirstValue(true);
try {
setPegRevision(Long.parseLong(pegRevisionString));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == LOCATION_REVISION) {
for (Iterator revisionsIterator = property.getValues().iterator(); revisionsIterator.hasNext(); ) {
try {
addRevision(Long.parseLong((String) revisionsIterator.next()));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
}
}
}
if (getPath() == null && !SVNRevision.isValidRevisionNumber(getPegRevision())) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Not all parameters passed."), SVNLogType.NETWORK);
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVGetLocksHandler extends DAVReportHandler {
private DAVGetLocksRequest myDAVRequest;
protected DAVGetLocksHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
protected DAVRequest getDAVRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVGetLocksRequest();
}
return myDAVRequest;
}
public void execute() throws SVNException {
setDAVResource(getRequestedDAVResource(false, false));
String responseBody = generateResponseBody();
try {
setResponseContentLength(responseBody.getBytes(UTF8_ENCODING).length);
} catch (UnsupportedEncodingException e) {
}
write(responseBody);
}
private String generateResponseBody() throws SVNException {
if (getDAVResource().getResourceURI().getPath() == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "get-locks-report run on resource which doesn't represent a path within a repository."), SVNLogType.NETWORK);
}
SVNLock[] locks = getDAVResource().getLocks();
StringBuffer xmlBuffer = new StringBuffer();
addXMLHeader(xmlBuffer, null);
for (int i = 0; i < locks.length; i++) {
addLock(locks[i], xmlBuffer);
}
addXMLFooter(xmlBuffer, null);
return xmlBuffer.toString();
}
private void addLock(SVNLock lock, StringBuffer xmlBuffer) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "lock", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "path", lock.getPath(), xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "token", lock.getID(), xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "creationdate", SVNDate.formatDate(lock.getCreationDate()), xmlBuffer);
if (lock.getExpirationDate() != null) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "expirationdate", SVNDate.formatDate(lock.getExpirationDate()), xmlBuffer);
}
if (lock.getOwner() != null) {
if (SVNEncodingUtil.isXMLSafe(lock.getOwner())) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "owner", lock.getOwner(), xmlBuffer);
} else {
String ownerEncoded = null;
try {
ownerEncoded = SVNBase64.byteArrayToBase64(lock.getOwner().getBytes(UTF8_ENCODING));
} catch (UnsupportedEncodingException e) {
ownerEncoded = SVNBase64.byteArrayToBase64(lock.getOwner().getBytes());
}
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "owner", ownerEncoded, ENCODING_ATTR, BASE64_ENCODING,
false, false, xmlBuffer);
}
}
if (lock.getComment() != null) {
if (SVNEncodingUtil.isXMLSafe(lock.getComment())) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "comment", lock.getComment(), xmlBuffer);
} else {
String commentEncoded = null;
try {
commentEncoded = SVNBase64.byteArrayToBase64(lock.getComment().getBytes(UTF8_ENCODING));
} catch (UnsupportedEncodingException e) {
commentEncoded = SVNBase64.byteArrayToBase64(lock.getComment().getBytes());
}
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "comment", commentEncoded, ENCODING_ATTR, BASE64_ENCODING,
false, false, xmlBuffer);
}
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "lock", xmlBuffer);
}
}

View File

@@ -0,0 +1,23 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import org.tmatesoft.svn.core.SVNException;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVGetLocksRequest extends DAVRequest {
protected void init() throws SVNException {
}
}

View File

@@ -0,0 +1,93 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVHandlerFactory {
public static final String METHOD_PROPFIND = "PROPFIND";
public static final String METHOD_OPTIONS = "OPTIONS";
public static final String METHOD_REPORT = "REPORT";
public static final String METHOD_GET = "GET";
public static final String METHOD_HEAD = "HEAD";
public static final String METHOD_POST = "POST";
public static final String METHOD_DELETE = "DELETE";
public static final String METHOD_TRACE = "TRACE";
public static final String METHOD_PROPPATCH = "PROPPATCH";
public static final String METHOD_COPY = "COPY";
public static final String METHOD_MOVE = "MOVE";
public static final String METHOD_PUT = "PUT";
public static final String METHOD_LOCK = "LOCK";
public static final String METHOD_UNLOCK = "UNLOCK";
public static final String METHOD_MKCOL = "MKCOL";
public static final String METHOD_VERSION_CONTROL = "VERSION-CONTROL";
public static final String METHOD_MKWORKSPACE = "MKWORKSPACE";
public static final String METHOD_MKACTIVITY = "MKACTIVITY";
public static final String METHOD_CHECKIN = "CHECKIN";
public static final String METHOD_CHECKOUT = "CHECKOUT";
public static final String METHOD_MERGE = "MERGE";
public static ServletDAVHandler createHandler(DAVRepositoryManager manager, HttpServletRequest request, HttpServletResponse response) throws SVNException {
String methodName = request.getMethod();
if (METHOD_PROPFIND.equals(methodName)) {
return new DAVPropfindHandler(manager, request, response);
} else if (METHOD_OPTIONS.equals(methodName)) {
return new DAVOptionsHandler(manager, request, response);
} else if (METHOD_GET.equals(methodName)) {
return new DAVGetHandler(manager, request, response);
} else if (METHOD_REPORT.equals(methodName)) {
return new DAVReportHandler(manager, request, response);
} else if (METHOD_MKACTIVITY.equals(methodName)) {
return new DAVMakeActivityHandler(manager, request, response);
} else if (METHOD_CHECKOUT.equals(methodName)) {
return new DAVCheckOutHandler(manager, request, response);
} else if (METHOD_PUT.equals(methodName)) {
return new DAVPutHandler(manager, request, response);
} else if (METHOD_DELETE.equals(methodName)) {
return new DAVDeleteHandler(manager, request, response);
} else if (METHOD_COPY.equals(methodName)) {
return new DAVCopyMoveHandler(manager, request, response, false);
} else if (METHOD_MOVE.equals(methodName)) {
return new DAVCopyMoveHandler(manager, request, response, true);
} else if (METHOD_MKCOL.equals(methodName)) {
return new DAVMakeCollectionHandler(manager, request, response);
} else if (METHOD_PROPPATCH.equals(methodName)) {
return new DAVPropPatchHandler(manager, request, response);
} else if (METHOD_MERGE.equals(methodName)) {
return new DAVMergeHandler(manager, request, response);
} else if (METHOD_LOCK.equals(methodName)) {
return new DAVLockHandler(manager, request, response);
} else if (METHOD_UNLOCK.equals(methodName)) {
return new DAVUnlockHandler(manager, request, response);
}
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Unknown request method ''{0}''", request.getMethod()),
SVNLogType.NETWORK);
return null;
}
}

View File

@@ -0,0 +1,49 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.LinkedList;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVInheritWalker implements IDAVResourceWalkHandler {
private boolean myIsSkipRoot;
private DAVResource myResource;
private DAVLock myLock;
public DAVInheritWalker(DAVResource resource, DAVLock lock, boolean skipRoot) {
myResource = resource;
myIsSkipRoot = skipRoot;
myLock = lock;
}
public DAVResponse handleResource(DAVResponse response, DAVResource resource, DAVLockInfoProvider lockInfoProvider, LinkedList ifHeaders,
int flags, DAVLockScope lockScope, CallType callType)
throws DAVException {
if (myIsSkipRoot && myResource.equals(resource)) {
return null;
}
lockInfoProvider.appendLock(resource, myLock);
return null;
}
}

View File

@@ -0,0 +1,146 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.dav.http.HTTPHeader;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceState;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVLockHandler extends ServletDAVHandler {
private DAVLockRequest myLockRequest;
protected DAVLockHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
public void execute() throws SVNException {
long readLength = readInput(false);
DAVDepth depth = null;
try {
depth = getRequestDepth(DAVDepth.DEPTH_INFINITY);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_BAD_REQUEST, null, null);
}
if (depth != DAVDepth.DEPTH_ZERO && depth != DAVDepth.DEPTH_INFINITY) {
sendError(HttpServletResponse.SC_BAD_REQUEST, "Depth must be 0 or \"infinity\" for LOCK.");
return;
}
DAVLockInfoProvider lockProvider = null;
DAVResource resource = getRequestedDAVResource(false, false);
try {
lockProvider = DAVLockInfoProvider.createLockInfoProvider(this, false);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, null);
}
boolean isNewLockRequest = false;
DAVLock lock = null;
if (readLength > 0) {
lock = getLockRequest().parseLockInfo(this, resource, getNamespaces());
isNewLockRequest = true;
}
DAVResourceState resourceState = getResourceState(resource);
try {
int flags = resourceState == DAVResourceState.NULL ? DAV_VALIDATE_PARENT : DAV_VALIDATE_RESOURCE;
flags |= DAV_VALIDATE_ADD_LD;
validateRequest(resource, depth, flags, isNewLockRequest ? lock.getScope() : null, null, lockProvider);
} catch (DAVException dave) {
DAVException next = new DAVException("Could not LOCK {0} due to a failed precondition (e.g. other locks).",
new Object[] { SVNEncodingUtil.xmlEncodeCDATA(resource.getResourceURI().getRequestURI(), true) }, dave.getResponseCode(), dave, 0);
throw next;
}
if (!isNewLockRequest) {
List lockTokens = null;
try {
lockTokens = getLockTokensList();
} catch (DAVException dave) {
DAVException next = new DAVException("The lock refresh for {0} failed because no lock tokens were specified in an \"If:\" header.",
new Object[] { SVNEncodingUtil.xmlEncodeCDATA(resource.getResourceURI().getRequestURI(), true) }, dave.getResponseCode(), dave, 0);
throw next;
}
String lockToken = (String) lockTokens.get(0);
lock = lockProvider.refreshLock(resource, lockToken, getTimeout());
} else {
if (lock.getTimeOutDate() != null) {
//TODO: add expiration date renewal
//Date timeoutDate = lock.getTimeOutDate();
}
lockProvider.addLock(lock, resource);
setResponseHeader(HTTPHeader.LOCK_TOKEN_HEADER, "<" + lock.getLockToken() + ">");
}
HttpServletResponse servletResponse = getHttpServletResponse();
servletResponse.setContentType(DEFAULT_XML_CONTENT_TYPE);
servletResponse.setStatus(HttpServletResponse.SC_OK);
try {
StringBuffer xmlBuffer = SVNXMLUtil.addXMLHeader(null);
DAVXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), null, null, xmlBuffer, true, false);
if (lock == null) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_DISCOVERY.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
} else {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_DISCOVERY.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, xmlBuffer);
xmlBuffer.append(DAVLockInfoProvider.getActiveLockXML(lock));
xmlBuffer.append('\n');
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_DISCOVERY.getName(), xmlBuffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), xmlBuffer);
getResponseWriter().write(xmlBuffer.toString());
} catch (IOException e) {
throw new DAVException(e.getMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
}
protected DAVRequest getDAVRequest() {
return getLockRequest();
}
private DAVLockRequest getLockRequest() {
if (myLockRequest == null) {
myLockRequest = new DAVLockRequest();
}
return myLockRequest;
}
}

View File

@@ -0,0 +1,585 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLock;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.dav.handlers.BasicDAVHandler;
import org.tmatesoft.svn.core.internal.io.dav.http.HTTPHeader;
import org.tmatesoft.svn.core.internal.io.fs.FSCommitter;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSLock;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionRoot;
import org.tmatesoft.svn.core.internal.server.dav.DAVConfig;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVErrorCode;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockRecType;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockType;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceHelper;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceURI;
import org.tmatesoft.svn.core.internal.server.dav.DAVServletUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVLockInfoProvider {
public static final String LOCK_BREAK_OPTION = "lock-break";
public static final String LOCK_STEAL_OPTION = "lock-steal";
public static final String RELEASE_LOCKS_OPTION = "release-locks";
public static final String KEEP_LOCKS_OPTION = "keep-locks";
public static final String NO_MERGE_RESPONSE = "no-merge-response";
private boolean myIsReadOnly;
private boolean myIsStealLock;
private boolean myIsBreakLock;
private boolean myIsKeepLocks;
private long myWorkingRevision;
private ServletDAVHandler myOwner;
public static DAVLockInfoProvider createLockInfoProvider(ServletDAVHandler owner, boolean readOnly) throws SVNException {
String clientOptions = owner.getRequestHeader(ServletDAVHandler.SVN_OPTIONS_HEADER);
DAVLockInfoProvider provider = new DAVLockInfoProvider();
provider.myOwner = owner;
provider.myIsReadOnly = readOnly;
if (clientOptions != null) {
if (clientOptions.indexOf(LOCK_BREAK_OPTION) != -1) {
provider.myIsBreakLock = true;
}
if (clientOptions.indexOf(LOCK_STEAL_OPTION) != -1) {
provider.myIsStealLock = true;
}
if (clientOptions.indexOf(KEEP_LOCKS_OPTION) != -1) {
provider.myIsKeepLocks = true;
}
}
String versionName = owner.getRequestHeader(ServletDAVHandler.SVN_VERSION_NAME_HEADER);
provider.myWorkingRevision = SVNRepository.INVALID_REVISION;
if (versionName != null) {
try {
provider.myWorkingRevision = Long.parseLong(versionName);
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
}
return provider;
}
public void addLock(DAVLock lock, DAVResource resource) throws DAVException {
DAVDepth depth = lock.getDepth();
if (!resource.isCollection()) {
depth = DAVDepth.DEPTH_ZERO;
}
appendLock(resource, lock);
if (depth != DAVDepth.DEPTH_ZERO) {
DAVResourceWalker walker = new DAVResourceWalker();
DAVLockWalker lockHandler = new DAVLockWalker(resource, lock);
DAVResponse response = walker.walk(this, resource, null, 0, null, DAVResourceWalker.DAV_WALKTYPE_NORMAL | DAVResourceWalker.DAV_WALKTYPE_AUTH,
lockHandler, DAVDepth.DEPTH_INFINITY);
if (response != null) {
throw new DAVException("Error(s) occurred on resources during the addition of a depth lock.", ServletDAVHandler.SC_MULTISTATUS, 0, response);
}
}
}
public DAVLock refreshLock(DAVResource resource, String lockToken, Date newTime) throws DAVException {
//TODO: add here authz check
FSFS fsfs = resource.getFSFS();
String path = resource.getResourceURI().getPath();
FSLock svnLock = null;
try {
svnLock = (FSLock) fsfs.getLockHelper(path, false);
} catch (SVNException e) {
throw DAVException.convertError(e.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Token doesn't point to a lock.", null);
}
if (svnLock == null || !svnLock.getID().equals(lockToken)) {
throw new DAVException("Lock refresh request doesn't match existing lock.", HttpServletResponse.SC_UNAUTHORIZED, DAVErrorCode.LOCK_SAVE_LOCK);
}
try {
svnLock = (FSLock) fsfs.lockPath(svnLock.getPath(), svnLock.getID(), resource.getUserName(), svnLock.getComment(), newTime,
SVNRepository.INVALID_REVISION, true, svnLock.isDAVComment());
} catch (SVNException e) {
SVNErrorMessage err = e.getErrorMessage();
if (err.getErrorCode() == SVNErrorCode.FS_NO_USER) {
throw new DAVException("Anonymous lock refreshing is not allowed.", HttpServletResponse.SC_UNAUTHORIZED, DAVErrorCode.LOCK_SAVE_LOCK);
}
throw DAVException.convertError(err, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to refresh existing lock.", null);
}
return convertSVNLockToDAVLock(svnLock, false, resource.exists());
}
public void inheritLocks(DAVResource resource, boolean useParent) throws DAVException {
DAVResource whichResource = resource;
if (useParent) {
DAVResource parentResource = DAVResourceHelper.createParentResource(resource);
if (parentResource == null) {
throw new DAVException("Could not fetch parent resource. Unable to inherit locks from the parent and apply them to this resource.",
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
whichResource = parentResource;
}
DAVLock lock = getLock(whichResource);
if (lock == null) {
return;
}
DAVInheritWalker inheritHandler = new DAVInheritWalker(resource, lock, !useParent);
DAVResourceWalker walker = new DAVResourceWalker();
walker.walk(this, whichResource, null, 0, null, DAVResourceWalker.DAV_WALKTYPE_NORMAL | DAVResourceWalker.DAV_WALKTYPE_LOCKNULL,
inheritHandler, DAVDepth.DEPTH_INFINITY);
}
public void appendLock(DAVResource resource, DAVLock lock) throws DAVException {
//TODO: add here authz check later
FSFS fsfs = resource.getFSFS();
String path = resource.getResourceURI().getPath();
if (!resource.exists()) {
SVNProperties revisionProps = new SVNProperties();
revisionProps.put(SVNRevisionProperty.AUTHOR, resource.getUserName());
DAVConfig config = resource.getRepositoryManager().getDAVConfig();
if (resource.isSVNClient()) {
throw new DAVException("Subversion clients may not lock nonexistent paths.", HttpServletResponse.SC_METHOD_NOT_ALLOWED,
DAVErrorCode.LOCK_SAVE_LOCK);
} else if (!config.isAutoVersioning()) {
throw new DAVException("Attempted to lock non-existent path; turn on autoversioning first.",
HttpServletResponse.SC_METHOD_NOT_ALLOWED, DAVErrorCode.LOCK_SAVE_LOCK);
}
long youngestRev = SVNRepository.INVALID_REVISION;
try {
youngestRev = resource.getLatestRevision();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not determine youngest revision", null);
}
FSTransactionInfo txnInfo = null;
try {
txnInfo = FSTransactionRoot.beginTransactionForCommit(youngestRev, revisionProps, fsfs);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not begin a transaction", null);
}
FSTransactionRoot root = null;
try {
root = fsfs.createTransactionRoot(txnInfo);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not begin a transaction", null);
}
FSCommitter committer = new FSCommitter(fsfs, root, txnInfo, resource.getLockTokens(), resource.getUserName());
try {
committer.makeFile(path);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not create empty file.", null);
}
try {
DAVServletUtil.attachAutoRevisionProperties(txnInfo, path, fsfs);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not create empty file.", null);
}
StringBuffer conflictPath = new StringBuffer();
try {
committer.commitTxn(true, true, null, conflictPath);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_CONFLICT, "Conflict when committing ''{0}''.",
new Object[] { conflictPath.toString() });
}
}
FSLock svnLock = convertDAVLockToSVNLock(lock, path, resource.isSVNClient(), ServletDAVHandler.getSAXParserFactory());
try {
fsfs.lockPath(path, svnLock.getID(), svnLock.getOwner(), svnLock.getComment(), svnLock.getExpirationDate(), myWorkingRevision,
myIsStealLock, svnLock.isDAVComment());
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NO_USER) {
throw new DAVException("Anonymous lock creation is not allowed.", HttpServletResponse.SC_UNAUTHORIZED,
DAVErrorCode.LOCK_SAVE_LOCK);
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create new lock.",
null);
}
myOwner.setResponseHeader(HTTPHeader.CREATION_DATE_HEADER, SVNDate.formatDate(svnLock.getCreationDate()));
myOwner.setResponseHeader(HTTPHeader.LOCK_OWNER_HEADER, svnLock.getOwner());
//TODO: add logging here later
}
public boolean hasLocks(DAVResource resource) throws DAVException {
if (resource.getResourceURI().getPath() == null) {
return false;
}
if (DAVHandlerFactory.METHOD_LOCK.equals(myOwner.getRequestMethod())) {
return false;
}
//TODO: add authz check here later
SVNLock lock = null;
try {
lock = resource.getLock();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to check path for a lock.", null);
}
return lock != null;
}
public DAVLock getLock(DAVResource resource) throws DAVException {
if (resource.getResourceURI().getPath() == null) {
return null;
}
if (DAVHandlerFactory.METHOD_LOCK.equals(myOwner.getRequestMethod())) {
return null;
}
//TODO: add authz check here later
DAVLock davLock = null;
FSLock lock = null;
try {
lock = (FSLock) resource.getLock();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to check path for a lock.", null);
}
if (lock != null) {
davLock = convertSVNLockToDAVLock(lock, myIsBreakLock, resource.exists());
myOwner.setResponseHeader(HTTPHeader.CREATION_DATE_HEADER, SVNDate.formatDate(lock.getCreationDate()));
myOwner.setResponseHeader(HTTPHeader.LOCK_OWNER_HEADER, lock.getOwner());
}
return davLock;
}
public DAVLock findLock(DAVResource resource, String lockToken) throws DAVException {
//TODO: add here authz check later
DAVLock davLock = null;
FSLock lock = null;
try {
lock = (FSLock) resource.getLock();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to look up lock by path.", null);
}
if (lock != null) {
if (!lockToken.equals(lock.getID())) {
throw new DAVException("Incoming token doesn't match existing lock.", HttpServletResponse.SC_BAD_REQUEST,
DAVErrorCode.LOCK_SAVE_LOCK);
}
davLock = convertSVNLockToDAVLock(lock, false, resource.exists());
myOwner.setResponseHeader(HTTPHeader.CREATION_DATE_HEADER, SVNDate.formatDate(lock.getCreationDate()));
myOwner.setResponseHeader(HTTPHeader.LOCK_OWNER_HEADER, lock.getOwner());
}
return davLock;
}
public void removeLock(DAVResource resource, String lockToken) throws DAVException {
DAVResourceURI resourceURI = resource.getResourceURI();
if (resourceURI.getPath() == null) {
return;
}
if (isKeepLocks()) {
return;
}
//TODO: add here authz check later
String token = null;
SVNLock lock = null;
if (lockToken == null) {
try {
lock = resource.getLock();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to check path for a lock.", null);
}
if (lock != null) {
token = lock.getID();
}
} else {
token = lockToken;
}
if (token != null) {
try {
resource.unlock(token, isBreakLock());
} catch (SVNException svne) {
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NO_USER) {
throw new DAVException("Anonymous lock removal is not allowed.", HttpServletResponse.SC_UNAUTHORIZED,
DAVErrorCode.LOCK_SAVE_LOCK);
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Failed to remove a lock.", null);
}
//TODO: add logging here
}
}
public String getSupportedLock(DAVResource resource) {
if (resource.isCollection()) {
return null;
}
StringBuffer buffer = new StringBuffer();
buffer.append('\n');
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_ENTRY.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_SCOPE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.EXCLUSIVE.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_SCOPE.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TYPE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.WRITE.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TYPE.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_ENTRY.getName(), buffer);
return buffer.toString();
}
public boolean isReadOnly() {
return myIsReadOnly;
}
public boolean isStealLock() {
return myIsStealLock;
}
public boolean isBreakLock() {
return myIsBreakLock;
}
public boolean isKeepLocks() {
return myIsKeepLocks;
}
public long getWorkingRevision() {
return myWorkingRevision;
}
public static String getActiveLockXML(DAVLock lock) {
StringBuffer buffer = new StringBuffer();
if (lock == null) {
return "";
}
if (lock.getRecType() == DAVLockRecType.INDIRECT_PARTIAL) {
//TODO: add debugging message here?
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.ACTIVE_LOCK.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TYPE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
if (lock.getType() == DAVLockType.WRITE) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.WRITE.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
} else {
//TODO: internal error. log something?
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TYPE.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_SCOPE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
if (lock.getScope() == DAVLockScope.EXCLUSIVE) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.EXCLUSIVE.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
} else if (lock.getScope() == DAVLockScope.SHARED) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.SHARED.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
} else {
//TODO: internal error. log something?
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_SCOPE.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.DEPTH.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append(lock.getDepth() == DAVDepth.DEPTH_INFINITY ? DAVDepth.DEPTH_INFINITY.toString() : DAVDepth.DEPTH_ZERO.toString());
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.DEPTH.getName(), buffer);
if (lock.getOwner() != null) {
buffer.append(lock.getOwner());
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TIMEOUT.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
if (lock.getTimeOutDate() == null) {
buffer.append("Infinite");
} else {
Date timeOutDate = lock.getTimeOutDate();
long now = System.currentTimeMillis();
long diff = timeOutDate.getTime() - now;
buffer.append("Second-");
//TODO: I'm not sure if I clearly understand what we must send here,
//have to test and review this later
buffer.append(diff);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TIMEOUT.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TOKEN.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append(lock.getLockToken());
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_TOKEN.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.ACTIVE_LOCK.getName(), buffer);
return buffer.toString();
}
public static FSLock convertDAVLockToSVNLock(DAVLock davLock, String path, boolean isSVNClient, SAXParserFactory saxParserFactory) throws DAVException {
if (davLock.getType() != DAVLockType.WRITE) {
throw new DAVException("Only 'write' locks are supported.", HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.LOCK_SAVE_LOCK);
}
if (davLock.getScope() != DAVLockScope.EXCLUSIVE) {
throw new DAVException("Only exclusive locks are supported.", HttpServletResponse.SC_BAD_REQUEST, DAVErrorCode.LOCK_SAVE_LOCK);
}
boolean isDAVComment = false;
String comment = null;
if (davLock.getOwner() != null) {
if (isSVNClient) {
try {
SAXParser xmlParser = saxParserFactory.newSAXParser();
XMLReader reader = xmlParser.getXMLReader();
FetchXMLHandler handler = new FetchXMLHandler(DAVElement.LOCK_OWNER);
reader.setContentHandler(handler);
reader.setDTDHandler(handler);
reader.setErrorHandler(handler);
reader.setEntityResolver(handler);
String owner = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + davLock.getOwner();
reader.parse(new InputSource(new ByteArrayInputStream(owner.getBytes())));
comment = handler.getData();
} catch (ParserConfigurationException e) {
throw new DAVException(e.getMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DAVErrorCode.LOCK_SAVE_LOCK);
} catch (SAXException e) {
throw new DAVException(e.getMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DAVErrorCode.LOCK_SAVE_LOCK);
} catch (IOException e) {
throw new DAVException(e.getMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DAVErrorCode.LOCK_SAVE_LOCK);
}
} else {
isDAVComment = true;
comment = davLock.getOwner();
}
}
return new FSLock(path, davLock.getLockToken(), davLock.getAuthUser(), comment, new Date(System.currentTimeMillis()),
davLock.getTimeOutDate(), isDAVComment);
}
public static DAVLock convertSVNLockToDAVLock(FSLock lock, boolean hideAuthUser, boolean exists) {
String authUser = null;
StringBuffer owner = null;
if (lock.getComment() != null) {
owner = new StringBuffer();
if (!lock.isDAVComment()) {
List namespaces = new ArrayList(1);
namespaces.add(DAVElement.DAV_NAMESPACE);
owner = DAVXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_OWNER.getName(), namespaces,
null, owner, false, false);
owner.append(SVNEncodingUtil.xmlEncodeCDATA(lock.getComment(), true));
owner = SVNXMLUtil.addXMLFooter(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.LOCK_OWNER.getName(), owner);
} else {
owner.append(lock.getComment());
}
}
if (!hideAuthUser) {
authUser = lock.getOwner();
}
return new DAVLock(authUser, DAVDepth.DEPTH_ZERO, exists, lock.getID(), owner != null ? owner.toString() : null, DAVLockRecType.DIRECT,
DAVLockScope.EXCLUSIVE, DAVLockType.WRITE, lock.getExpirationDate());
}
public static class GetLocksCallType {
public static final GetLocksCallType RESOLVED = new GetLocksCallType();
public static final GetLocksCallType PARTIAL = new GetLocksCallType();
public static final GetLocksCallType COMPLETE = new GetLocksCallType();
private GetLocksCallType() {
}
}
private static class FetchXMLHandler extends BasicDAVHandler {
private String myData;
private DAVElement myElement;
public FetchXMLHandler(DAVElement element) {
myElement = element;
init();
}
public String getData() {
return myData;
}
protected void endElement(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
if (element == myElement) {
myData = cdata.toString();
}
}
protected void startElement(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockRecType;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockType;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVLockRequest extends DAVRequest {
private static final DAVElement LOCK_INFO = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "lockinfo");
public DAVLock parseLockInfo(DAVLockHandler handler, DAVResource resource, List namespaces) throws DAVException {
DAVDepth depth = null;
try {
depth = handler.getRequestDepth(DAVDepth.DEPTH_INFINITY);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_BAD_REQUEST, null, null);
}
if (depth != DAVDepth.DEPTH_ONE && depth != DAVDepth.DEPTH_ZERO) {
throw new DAVException("An invalid Depth header was specified.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
Date timeout = handler.getTimeout();
String lockToken = null;
try {
lockToken = FSRepositoryUtil.generateLockToken();
} catch (SVNException e) {
DAVException first = DAVException.convertError(e.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to generate a lock token.", null);
DAVException next = new DAVException("Could not parse the lockinfo due to an internal problem creating a lock structure.", first.getResponseCode(), first, 0);
throw next;
}
DAVElementProperty rootElement = null;
try {
rootElement = getRoot();
} catch (SVNException e) {
throw DAVException.convertError(e.getErrorMessage(), HttpServletResponse.SC_BAD_REQUEST,
"Could not parse the lockinfo, malformed xml request", null);
}
String owner = null;
DAVLockScope lockScope = DAVLockScope.UNKNOWN;
DAVLockType lockType = DAVLockType.UNKNOWN;
for (Iterator childrenIter = rootElement.getChildren().iterator(); childrenIter.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) childrenIter.next();
DAVElement childElementName = childElement.getName();
if (childElementName == DAVElement.LOCK_TYPE && childElement.getChildren() != null && lockType == DAVLockType.UNKNOWN) {
DAVElementProperty writeChild = childElement.getChild(DAVElement.WRITE);
if (writeChild != null) {
lockType = DAVLockType.WRITE;
continue;
}
}
if (childElementName == DAVElement.LOCK_SCOPE && childElement.getChildren() != null && lockScope == DAVLockScope.UNKNOWN) {
if (childElement.getChild(DAVElement.EXCLUSIVE) != null) {
lockScope = DAVLockScope.EXCLUSIVE;
} else if (childElement.getChild(DAVElement.SHARED) != null) {
lockScope = DAVLockScope.SHARED;
}
if (lockScope != DAVLockScope.UNKNOWN) {
continue;
}
}
if (childElementName == DAVElement.LOCK_OWNER) {
//TODO: maybe make this recursive for all possible subelements
StringBuffer buffer = new StringBuffer();
String namespace = childElementName.getNamespace();
buffer.append("<");
if (namespace == null || "".equals(namespace)) {
buffer.append(childElementName.getName());
} else {
buffer.append(SVNXMLUtil.PREFIX_MAP.get(namespace));
buffer.append(":");
buffer.append(childElementName.getName());
}
Map attributes = childElement.getAttributes();
if (attributes != null) {
for (Iterator attrsIter = attributes.keySet().iterator(); attrsIter.hasNext();) {
String attrName = (String) attrsIter.next();
String attrValue = (String) attributes.get(attrName);
buffer.append(" ");
buffer.append(attrName);
buffer.append("=\"");
buffer.append(attrValue);
buffer.append("\"");
}
}
for (Iterator namespacesIter = namespaces.iterator(); namespacesIter.hasNext();) {
String nextNamespace = (String) namespacesIter.next();
buffer.append(" xmlns:");
buffer.append(SVNXMLUtil.PREFIX_MAP.get(nextNamespace));
buffer.append("=\"");
buffer.append(nextNamespace);
buffer.append("\"");
}
if (childElement.isEmpty()) {
buffer.append(" />");
} else {
buffer.append(">");
buffer.append(SVNEncodingUtil.xmlEncodeCDATA(childElement.getFirstValue(false), false));
buffer.append("</");
if (namespace == null || "".equals(namespace)) {
buffer.append(childElementName.getName());
} else {
buffer.append(SVNXMLUtil.PREFIX_MAP.get(namespace));
buffer.append(":");
buffer.append(childElementName.getName());
}
buffer.append(">");
}
owner = buffer.toString();
continue;
}
throw new DAVException("The server cannot satisfy the LOCK request due to an unknown XML element (\"{0}\") within the DAV:lockinfo element.",
new Object[] { childElementName.getName() }, HttpServletResponse.SC_PRECONDITION_FAILED, 0);
}
return new DAVLock(resource.getUserName(), depth, resource.exists(), lockToken, owner, DAVLockRecType.DIRECT, lockScope, lockType, timeout);
}
protected void init() throws SVNException {
if (getRoot().getName() != LOCK_INFO) {
invalidXMLRoot();
}
}
protected DAVElementProperty getRoot() throws SVNException {
if (getRootElement() == null) {
invalidXMLRoot();
}
return getRootElement();
}
protected void invalidXMLRoot() throws SVNException {
throw new DAVException("The request body contains an unexpected XML root element.", null, HttpServletResponse.SC_BAD_REQUEST,
null, SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
}

View File

@@ -0,0 +1,57 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.LinkedList;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVLockWalker implements IDAVResourceWalkHandler {
private DAVResource myResource;
private DAVLock myLock;
public DAVLockWalker(DAVResource resource, DAVLock lock) {
myResource = resource;
myLock = lock;
}
public DAVResponse handleResource(DAVResponse response, DAVResource resource, DAVLockInfoProvider lockInfoProvider, LinkedList ifHeaders, int flags,
DAVLockScope lockScope, CallType callType)
throws DAVException {
if (myResource.equals(resource)) {
return null;
}
try {
lockInfoProvider.appendLock(resource, myLock);
} catch (DAVException dave) {
if (DAVServlet.isHTTPServerError(dave.getResponseCode())) {
throw dave;
}
DAVResponse resp = new DAVResponse(null, resource.getResourceURI().getRequestURI(), response, null, dave.getResponseCode());
return resp;
}
return null;
}
}

View File

@@ -0,0 +1,189 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.wc.SVNRevision;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVLogHandler extends DAVReportHandler implements ISVNLogEntryHandler {
private DAVLogRequest myDAVRequest;
private int myDepth = 0;
private DAVReportHandler myCommonReportHandler;
public DAVLogHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
myCommonReportHandler = commonReportHandler;
}
protected DAVRequest getDAVRequest() {
return getLogRequest();
}
private DAVLogRequest getLogRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVLogRequest();
}
return myDAVRequest;
}
private int getDepth() {
return myDepth;
}
private void increaseDepth() {
myDepth++;
}
private void decreaseDepth() {
myDepth--;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace(null);
setDAVResource(getRequestedDAVResource(false, false));
writeXMLHeader(null);
for (int i = 0; i < getLogRequest().getTargetPaths().length; i++) {
String currentPath = getLogRequest().getTargetPaths()[i];
DAVPathUtil.testCanonical(currentPath);
getLogRequest().getTargetPaths()[i] = SVNPathUtil.append(getDAVResource().getResourceURI().getPath(), currentPath);
}
DAVLogRequest logRequest = getLogRequest();
getDAVResource().getRepository().log(logRequest.getTargetPaths(), logRequest.getStartRevision(),
logRequest.getEndRevision(), logRequest.isDiscoverChangedPaths(), logRequest.isStrictNodeHistory(),
logRequest.getLimit(), logRequest.isIncludeMergedRevisions(), logRequest.getRevisionProperties(),
this);
writeXMLFooter(null);
}
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
if (logEntry.getRevision() == DAVResource.INVALID_REVISION) {
if (getDepth() == 0) {
return;
}
decreaseDepth();
}
StringBuffer xmlBuffer = new StringBuffer();
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "log-item", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_NAME.getName(), String.valueOf(logEntry.getRevision()), xmlBuffer);
boolean noCustomProperties = getLogRequest().isCustomPropertyRequested();
SVNProperties revProps = logEntry.getRevisionProperties();
for (Iterator iterator = revProps.nameSet().iterator(); iterator.hasNext();) {
String propName = (String) iterator.next();
String propValue = revProps.getStringValue(propName);
if (SVNRevisionProperty.AUTHOR.equals(propName)) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CREATOR_DISPLAY_NAME.getName(), propValue, null,
false, true, xmlBuffer);
} else if (SVNRevisionProperty.DATE.equals(propName)) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "date", propValue, null, false, true, xmlBuffer);
} else if (SVNRevisionProperty.LOG.equals(propName)) {
String comment = SVNEncodingUtil.fuzzyEscape(propValue);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.COMMENT.getName(), comment, null, false, true, xmlBuffer);
} else {
noCustomProperties = false;
String encodedPropName = SVNEncodingUtil.xmlEncodeCDATA(propName, false);
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "revprop", propValue, NAME_ATTR, encodedPropName, false,
true, xmlBuffer);
}
}
if (noCustomProperties) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "no-custom-revprops", SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
if (logEntry.hasChildren()) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "has-children", SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
increaseDepth();
}
write(xmlBuffer);
if (logEntry.getChangedPaths() != null) {
for (Iterator iterator = logEntry.getChangedPaths().entrySet().iterator(); iterator.hasNext();) {
Map.Entry pathEntry = (Map.Entry) iterator.next();
String path = (String) pathEntry.getKey();
SVNLogEntryPath logEntryPath = (SVNLogEntryPath) pathEntry.getValue();
addChangedPathTag(path, logEntryPath);
}
}
xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "log-item", null);
write(xmlBuffer);
}
private void addChangedPathTag(String path, SVNLogEntryPath logEntryPath) throws SVNException {
StringBuffer xmlBuffer = new StringBuffer();
switch (logEntryPath.getType()) {
case SVNLogEntryPath.TYPE_ADDED:
if (logEntryPath.getCopyPath() != null && SVNRevision.isValidRevisionNumber(logEntryPath.getCopyRevision())) {
Map attrs = new SVNHashMap();
attrs.put(COPYFROM_PATH_ATTR, logEntryPath.getCopyPath());
attrs.put(COPYFROM_REVISION_ATTR, String.valueOf(logEntryPath.getCopyRevision()));
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "added-path", path, attrs, xmlBuffer);
} else {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "added-path", path, xmlBuffer);
}
break;
case SVNLogEntryPath.TYPE_REPLACED:
Map attrs = null;
if (logEntryPath.getCopyPath() != null && SVNRevision.isValidRevisionNumber(logEntryPath.getCopyRevision())) {
attrs = new SVNHashMap();
attrs.put(COPYFROM_PATH_ATTR, logEntryPath.getCopyPath());
attrs.put(COPYFROM_REVISION_ATTR, String.valueOf(logEntryPath.getCopyRevision()));
}
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "replaced-path", path, attrs, xmlBuffer);
break;
case SVNLogEntryPath.TYPE_MODIFIED:
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "modified-path", path, xmlBuffer);
break;
case SVNLogEntryPath.TYPE_DELETED:
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "deleted-path", path, xmlBuffer);
break;
default:
break;
}
write(xmlBuffer);
}
}

View File

@@ -0,0 +1,215 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVLogRequest extends DAVRequest {
private static final DAVElement DISCOVER_CHANGED_PATHS = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "discover-changed-paths");
private static final DAVElement INCLUDE_MERGED_REVISIONS = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "include-merged-revisions");
private static final DAVElement STRICT_NODE_HISTORY = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "strict-node-history");
private static final DAVElement OMIT_LOG_TEXT = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "omit-log-text");
private static final DAVElement LIMIT = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "limit");
private static final DAVElement ALL_REVPROPS = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "all-revprops");
private static final DAVElement REVPROP = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "revprop");
private static final String[] DEFAULT_REVISION_PROPERTIES = new String[]{ SVNRevisionProperty.AUTHOR, SVNRevisionProperty.DATE, SVNRevisionProperty.LOG };
private boolean myDiscoverChangedPaths = false;
private boolean myStrictNodeHistory = false;
private boolean myIncludeMergedRevisions = false;
private boolean myOmitLogText = false;
private long myStartRevision = DAVResource.INVALID_REVISION;
private long myEndRevision = DAVResource.INVALID_REVISION;
private long myLimit = 0;
private Collection myTargetPathsCollection;
private String[] myTargetPathsArray;
private Collection myRevisionPropertiesCollection;
private String[] myRevisionPropertiesArray;
private boolean myCustomPropertyRequested = false;
public boolean isDiscoverChangedPaths() {
return myDiscoverChangedPaths;
}
private void setDiscoverChangedPaths(boolean discoverChangedPaths) {
myDiscoverChangedPaths = discoverChangedPaths;
}
public boolean isStrictNodeHistory() {
return myStrictNodeHistory;
}
private void setStrictNodeHistory(boolean strictNodeHistory) {
myStrictNodeHistory = strictNodeHistory;
}
public boolean isIncludeMergedRevisions() {
return myIncludeMergedRevisions;
}
private void setIncludeMergedRevisions(boolean includeMergedRevisions) {
myIncludeMergedRevisions = includeMergedRevisions;
}
public boolean isOmitLogText() {
return myOmitLogText;
}
private void setOmitLogText(boolean omitLogText) {
myOmitLogText = omitLogText;
}
public long getStartRevision() {
return myStartRevision;
}
private void setStartRevision(long startRevision) {
myStartRevision = startRevision;
}
public long getEndRevision() {
return myEndRevision;
}
private void setEndRevision(long endRevision) {
myEndRevision = endRevision;
}
public long getLimit() {
return myLimit;
}
private void setLimit(long limit) {
myLimit = limit;
}
public String[] getTargetPaths() {
if (myTargetPathsArray == null && myTargetPathsCollection != null) {
myTargetPathsArray = (String[]) myTargetPathsCollection.toArray(new String[myTargetPathsCollection.size()]);
}
return myTargetPathsArray;
}
private void addTargetPaths(Collection targetPaths) {
if (myTargetPathsCollection == null) {
myTargetPathsCollection = new LinkedList();
}
myTargetPathsCollection.addAll(targetPaths);
}
public String[] getRevisionProperties() {
if (myRevisionPropertiesArray == null && myRevisionPropertiesCollection != null) {
myRevisionPropertiesArray = (String[]) myRevisionPropertiesCollection.toArray(new String[myRevisionPropertiesCollection.size()]);
}
return myRevisionPropertiesArray;
}
private void addRevisionProperties(Collection revisionProperties) {
if (myRevisionPropertiesCollection == null) {
myRevisionPropertiesCollection = new LinkedList();
}
myRevisionPropertiesCollection.addAll(revisionProperties);
}
private void setRevisionProperties(String[] revisionProperties) {
myRevisionPropertiesArray = revisionProperties;
}
public boolean isCustomPropertyRequested() {
return myCustomPropertyRequested;
}
private void setCustomPropertyRequested(boolean customPropertyRequested) {
myCustomPropertyRequested = customPropertyRequested;
}
protected void init() throws SVNException {
boolean revisionPropertyRequested = false;
List children = getRootElement().getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
DAVElementProperty property = (DAVElementProperty) iterator.next();
DAVElement element = property.getName();
if (element == DISCOVER_CHANGED_PATHS) {
setDiscoverChangedPaths(true);
} else if (element == STRICT_NODE_HISTORY) {
setStrictNodeHistory(true);
} else if (element == INCLUDE_MERGED_REVISIONS) {
setIncludeMergedRevisions(true);
} else if (element == OMIT_LOG_TEXT) {
setOmitLogText(true);
} else if (element == DAVElement.START_REVISION) {
String revisionString = property.getFirstValue(true);
try {
setStartRevision(Long.parseLong(revisionString));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == DAVElement.END_REVISION) {
String revisionString = property.getFirstValue(true);
try {
setEndRevision(Long.parseLong(revisionString));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == LIMIT) {
String limitString = property.getFirstValue(true);
setLimit(Integer.parseInt(limitString));
} else if (element == DAVElement.PATH) {
Collection paths = property.getValues();
if (paths != null) {
addTargetPaths(paths);
}
} else if (element == ALL_REVPROPS) {
setCustomPropertyRequested(true);
revisionPropertyRequested = true;
} else if (element == REVPROP) {
Collection properties = property.getValues();
addRevisionProperties(properties);
setCustomPropertyRequested(containsCustomProperty(properties));
revisionPropertyRequested = true;
}
}
if (!revisionPropertyRequested) {
setRevisionProperties(DEFAULT_REVISION_PROPERTIES);
}
}
private boolean containsCustomProperty(Collection requestedProperties) {
for (Iterator iterator = requestedProperties.iterator(); iterator.hasNext();) {
String property = (String) iterator.next();
if (!SVNRevisionProperty.AUTHOR.equals(property) && !SVNRevisionProperty.DATE.equals(property) &&
!SVNRevisionProperty.LOG.equals(property)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,79 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRepository;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVServletUtil;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVMakeActivityHandler extends ServletDAVHandler {
private FSFS myFSFS;
public DAVMakeActivityHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
public void execute() throws SVNException {
DAVResource resource = getRequestedDAVResource(false, false);
FSRepository repos = (FSRepository) resource.getRepository();
myFSFS = repos.getFSFS();
readInput(true);
if (resource.exists()) {
throw new DAVException("<DAV:resource-must-be-null/>", HttpServletResponse.SC_CONFLICT, SVNLogType.NETWORK);
}
if (!resource.canBeActivity()) {
throw new DAVException("<DAV:activity-location-ok/>", HttpServletResponse.SC_FORBIDDEN, SVNLogType.NETWORK);
}
try {
makeActivity(resource);
} catch (DAVException dave) {
throw new DAVException("Could not create activity {0}.", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(resource.getResourceURI().getURI()) },
dave.getResponseCode(), null, SVNLogType.NETWORK, Level.FINE, dave, null, null, 0, null);
}
setResponseHeader(CACHE_CONTROL_HEADER, CACHE_CONTROL_VALUE);
handleDAVCreated(resource.getResourceURI().getURI(), "Activity", false);
}
protected DAVRequest getDAVRequest() {
return null;
}
private void makeActivity(DAVResource resource) throws DAVException {
FSTransactionInfo txnInfo = DAVServletUtil.createActivity(resource, myFSFS);
DAVServletUtil.storeActivity(resource, txnInfo.getTxnId());
resource.setExists(true);
resource.setTxnName(txnInfo.getTxnId());
}
}

View File

@@ -0,0 +1,125 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.http.HTTPHeader;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceState;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVMakeCollectionHandler extends ServletDAVHandler {
protected DAVMakeCollectionHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
public void execute() throws SVNException {
int status = processMkColBody();
if (status != HttpServletResponse.SC_OK) {
sendError(status, null);
return;
}
DAVResource resource = getRequestedDAVResource(false, false);
if (resource.exists()) {
sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, null);
return;
}
DAVResourceState resourceState = getResourceState(resource);
validateRequest(resource, DAVDepth.DEPTH_ZERO, resourceState == DAVResourceState.NULL ? DAV_VALIDATE_PARENT : DAV_VALIDATE_RESOURCE,
null, null, null);
DAVException err1 = null;
DAVException err2 = null;
DAVAutoVersionInfo avInfo = autoCheckOut(resource, true);
resource.setCollection(true);
try {
createdCollection(resource);
} catch (DAVException dave) {
err1 = dave;
}
try {
autoCheckIn(resource, err1 != null, false, avInfo);
} catch (DAVException dave) {
err2 = dave;
}
if (err1 != null) {
throw err1;
}
if (err2 != null) {
err1 = new DAVException("The MKCOL was successful, but there was a problem opening the lock database which prevents inheriting locks from the parent resources.",
err2.getResponseCode(), err2, 0);
}
DAVLockInfoProvider lockProvider = null;
try {
lockProvider = DAVLockInfoProvider.createLockInfoProvider(this, false);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"The MKCOL was successful, but there was a problem opening the lock database which prevents inheriting locks from the parent resources.",
null);
}
notifyCreated(resource, lockProvider, resourceState, DAVDepth.DEPTH_ZERO);
handleDAVCreated(null, "Collection", false);
}
protected DAVRequest getDAVRequest() {
return null;
}
private int processMkColBody() throws SVNException {
String transferEncoding = getRequestHeader(HTTPHeader.TRANSFER_ENCODING_HEADER);
String contentLength = getRequestHeader(HTTPHeader.CONTENT_LENGTH_HEADER);
boolean readChunked = false;
int remaining = 0;
if (transferEncoding != null) {
if (!transferEncoding.equalsIgnoreCase("chunked")) {
//throw new DAVException("Unknown Transfer-Encoding ", new Object[] { transferEncoding }, HttpServletResponse.SC_NOT_IMPLEMENTED, 0);
return HttpServletResponse.SC_NOT_IMPLEMENTED;
}
readChunked = true;
} else if (contentLength != null) {
try {
remaining = Integer.parseInt(contentLength.trim());
} catch (NumberFormatException nfe) {
//throw new DAVException("Invalid Content-Length {0}", new Object[] { contentLength }, HttpServletResponse.SC_BAD_REQUEST, 0);
return HttpServletResponse.SC_BAD_REQUEST;
}
}
if (readChunked || remaining > 0) {
//throw new DAVException(DAVServlet.getStatusLine(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, 0);
return HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
}
readInput(true);
return HttpServletResponse.SC_OK;
}
}

View File

@@ -0,0 +1,410 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNRevisionProperty;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSCommitter;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSPathChange;
import org.tmatesoft.svn.core.internal.io.fs.FSPathChangeKind;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionRoot;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceKind;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import org.tmatesoft.svn.core.internal.server.dav.DAVServletUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVMergeHandler extends ServletDAVHandler {
private DAVMergeRequest myDAVRequest;
protected DAVMergeHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
public void execute() throws SVNException {
long readLength = readInput(false);
if (readLength <= 0) {
getMergeRequest().invalidXMLRoot();
}
DAVMergeRequest requestXMLObject = getMergeRequest();
DAVElementProperty rootElement = requestXMLObject.getRoot();
DAVElementProperty sourceElement = rootElement.getChild(DAVElement.SOURCE);
if (sourceElement == null) {
throw new DAVException("The DAV:merge element must contain a DAV:source element.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
DAVElementProperty hrefElement = sourceElement.getChild(DAVElement.HREF);
if (hrefElement == null) {
throw new DAVException("The DAV:source element must contain a DAV:href element.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
String source = hrefElement.getFirstValue(false);
URI uri = null;
try {
uri = DAVServletUtil.lookUpURI(source, getRequest(), false);
} catch (DAVException dave) {
if (dave.getResponseCode() == HttpServletResponse.SC_BAD_REQUEST) {
throw dave;
}
response(dave.getMessage(), DAVServlet.getStatusLine(dave.getResponseCode()), dave.getResponseCode());
}
String path = uri.getPath();
DAVRepositoryManager manager = getRepositoryManager();
String resourceContext = manager.getResourceContext();
if (!path.startsWith(resourceContext)) {
throw new DAVException("Destination url starts with a wrong context", HttpServletResponse.SC_BAD_REQUEST, 0);
}
//TODO: cut away the servlet context part
path = path.substring(resourceContext.length());
DAVResource srcResource = getRequestedDAVResource(false, false, path);
//NOTE: for now this all are no-ops, just commented them for a while
//boolean noAutoMerge = rootElement.hasChild(DAVElement.NO_AUTO_MERGE);
//boolean noCheckOut = rootElement.hasChild(DAVElement.NO_CHECKOUT);
//DAVElementProperty propElement = rootElement.getChild(DAVElement.PROP);
DAVResource resource = getRequestedDAVResource(false, false);
if (!resource.exists()) {
sendError(HttpServletResponse.SC_NOT_FOUND, null);
return;
}
setResponseHeader(CACHE_CONTROL_HEADER, CACHE_CONTROL_VALUE);
String response = null;
try {
response = merge(resource, srcResource);
} catch (DAVException dave) {
throw new DAVException("Could not MERGE resource \"{0}\" into \"{1}\".", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(source),
SVNEncodingUtil.xmlEncodeCDATA(getURI()) }, dave.getResponseCode(), null, SVNLogType.NETWORK, Level.FINE, dave, null,
null, 0, null);
}
try {
setResponseContentLength(response.getBytes(UTF8_ENCODING).length);
} catch (UnsupportedEncodingException e) {
}
try {
getResponseWriter().write(response);
} catch (IOException ioe) {
throw new DAVException(ioe.getMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, SVNErrorCode.IO_ERROR.getCode());
}
}
protected DAVRequest getDAVRequest() {
return getMergeRequest();
}
private String merge(DAVResource targetResource, DAVResource sourceResource) throws DAVException {
boolean disableMergeResponse = false;
if (sourceResource.getType() != DAVResourceType.ACTIVITY) {
throw new DAVException("MERGE can only be performed using an activity as the source [at this time].", null,
HttpServletResponse.SC_METHOD_NOT_ALLOWED, null, SVNLogType.NETWORK, Level.FINE, null, DAVXMLUtil.SVN_DAV_ERROR_TAG,
DAVElement.SVN_DAV_ERROR_NAMESPACE, SVNErrorCode.INCORRECT_PARAMS.getCode(), null);
}
Map locks = parseLocks(getMergeRequest().getRootElement(), targetResource.getResourceURI().getPath());
if (!locks.isEmpty()) {
sourceResource.setLockTokens(locks.values());
}
FSFS fsfs = sourceResource.getFSFS();
String txnName = sourceResource.getTxnName();
FSTransactionInfo txn = DAVServletUtil.openTxn(fsfs, txnName);
FSTransactionRoot txnRoot = null;
try {
txnRoot = fsfs.createTransactionRoot(txn);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not open a (transaction) root in the repository", null);
}
FSCommitter committer = getCommitter(sourceResource.getFSFS(), txnRoot, txn,
sourceResource.getLockTokens(), sourceResource.getUserName());
StringBuffer buffer = new StringBuffer();
SVNErrorMessage[] postCommitHookErr = new SVNErrorMessage[1];
String postCommitErrMessage = null;
long newRev = -1;
try {
newRev = committer.commitTxn(true, true, postCommitHookErr, buffer);
} catch (SVNException svne) {
if (postCommitHookErr[0] == null) {
try {
FSCommitter.abortTransaction(fsfs, txnName);
} catch (SVNException svne1) {
//
}
if (svne.getErrorMessage().getErrorCode() == SVNErrorCode.FS_CONFLICT) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_CONFLICT,
"A conflict occurred during the MERGE processing. The problem occurred with the \"{0}\" resource.",
new Object[] { buffer.toString() });
}
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_CONFLICT,
"An error occurred while committing the transaction.", null);
}
}
if (postCommitHookErr[0] != null) {
SVNErrorMessage childErr = postCommitHookErr[0].getChildErrorMessage();
if (childErr != null && childErr.getMessage() != null) {
postCommitErrMessage = childErr.getMessage();
}
}
//TODO: maybe add logging here
DAVServletUtil.storeActivity(sourceResource, "");
String clientOptions = sourceResource.getClientOptions();
if (clientOptions != null) {
if (clientOptions.indexOf(DAVLockInfoProvider.RELEASE_LOCKS_OPTION) != -1 && !locks.isEmpty()) {
for (Iterator locksIter = locks.keySet().iterator(); locksIter.hasNext();) {
String path = (String) locksIter.next();
String lockToken = (String) locks.get(path);
try {
fsfs.unlockPath(path, lockToken, sourceResource.getUserName(), false, true);
} catch (SVNException svne) {
// TODO: ignore exceptions. maybe add logging
}
}
}
if (clientOptions.indexOf(DAVLockInfoProvider.NO_MERGE_RESPONSE) != -1) {
disableMergeResponse = true;
}
}
return response(fsfs, newRev, postCommitErrMessage, disableMergeResponse);
}
private String response(FSFS fsfs, long newRev, String postCommitErr, boolean disableMergeResponse) throws DAVException {
FSRevisionRoot root = null;
try {
root = fsfs.createRevisionRoot(newRev);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not open the FS root for the revision just committed.", null);
}
String vcc = DAVPathUtil.buildURI(getRepositoryManager().getResourceContext(), DAVResourceKind.VCC, -1, null, false);
StringBuffer buffer = new StringBuffer();
Map prefixMap = new HashMap();
Collection namespaces = new LinkedList();
namespaces.add(DAVElement.DAV_NAMESPACE);
prefixMap.put(DAVElement.DAV_NAMESPACE, SVNXMLUtil.DAV_NAMESPACE_PREFIX);
String postCommitErrElement = null;
if (postCommitErr != null) {
namespaces.add(DAVElement.SVN_NAMESPACE);
prefixMap.put(DAVElement.SVN_NAMESPACE, SVNXMLUtil.SVN_NAMESPACE_PREFIX);
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, DAVElement.POST_COMMIT_ERROR.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA,
null, buffer);
buffer.append(postCommitErr);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, DAVElement.POST_COMMIT_ERROR.getName(), buffer);
postCommitErrElement = buffer.toString();
buffer.delete(0, buffer.length());
} else {
postCommitErrElement = "";
}
String creationDate = null;
String creatorDisplayName = null;
try {
SVNProperties revProps = fsfs.getRevisionProperties(newRev);
creationDate = revProps.getStringValue(SVNRevisionProperty.DATE);
creatorDisplayName = revProps.getStringValue(SVNRevisionProperty.AUTHOR);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not get author of newest revision", null);
}
SVNXMLUtil.addXMLHeader(buffer);
SVNXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.MERGE_RESPONSE.getName(), namespaces, prefixMap,
null, buffer, true);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.UPDATE_SET.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), vcc, null, true, true, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESOURCE_TYPE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.BASELINE.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING | SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESOURCE_TYPE.getName(), buffer);
buffer.append(postCommitErrElement);
buffer.append('\n');
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_NAME.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append(newRev);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_NAME.getName(), buffer);
if (creationDate != null ) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CREATION_DATE.getName(), creationDate, null, true, true, buffer);
}
if (creatorDisplayName != null ) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CREATOR_DISPLAY_NAME.getName(), creatorDisplayName, null, true,
true, buffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append("HTTP/1.1 200 OK");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE.getName(), buffer);
if (!disableMergeResponse) {
try {
doResources(root, buffer);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error constructing resource list.", null);
}
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.UPDATE_SET.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.MERGE_RESPONSE.getName(), buffer);
return buffer.toString();
}
private void doResources(FSRevisionRoot root, StringBuffer buffer) throws SVNException {
Map changedPaths = root.getChangedPaths();
Map sentPaths = new HashMap();
for (Iterator pathsIter = changedPaths.keySet().iterator(); pathsIter.hasNext();) {
String path = (String) pathsIter.next();
FSPathChange pathChange = (FSPathChange) changedPaths.get(path);
boolean sendSelf = false;
boolean sendParent = false;
FSPathChangeKind changeKind = pathChange.getChangeKind();
if (changeKind == FSPathChangeKind.FS_PATH_CHANGE_DELETE) {
sendSelf = false;
sendParent = true;
} else if (changeKind == FSPathChangeKind.FS_PATH_CHANGE_ADD || changeKind == FSPathChangeKind.FS_PATH_CHANGE_REPLACE) {
sendSelf = true;
sendParent = true;
} else {
sendSelf = true;
sendParent = false;
}
if (sendSelf) {
if (!sentPaths.containsKey(path)) {
SVNNodeKind pathKind = root.checkNodeKind(path);
sendResponse(root, path, pathKind == SVNNodeKind.DIR, buffer);
sentPaths.put(path, path);
}
}
if (sendParent) {
String parentPath = SVNPathUtil.removeTail(path);
if (!sentPaths.containsKey(parentPath)) {
sendResponse(root, parentPath, true, buffer);
sentPaths.put(parentPath, parentPath);
}
}
}
}
private void sendResponse(FSRevisionRoot root, String path, boolean isDir, StringBuffer buffer) {
String context = getRepositoryManager().getResourceContext();
String href = DAVPathUtil.buildURI(context, DAVResourceKind.PUBLIC, -1, path, false);
long revToUse = DAVServletUtil.getSafeCreatedRevision(root, path);
String vsnURL = DAVPathUtil.buildURI(context, DAVResourceKind.VERSION, revToUse, path, false);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE.getName(),
SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), href, null, true, true, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
if (isDir) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESOURCE_TYPE.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null,
buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.COLLECTION.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESOURCE_TYPE.getName(), buffer);
} else {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESOURCE_TYPE.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING |
SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CHECKED_IN.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), vsnURL, null, true, true, buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CHECKED_IN.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append("HTTP/1.1 200 OK");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE.getName(), buffer);
}
private DAVMergeRequest getMergeRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVMergeRequest();
}
return myDAVRequest;
}
}

View File

@@ -0,0 +1,120 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNMergeInfo;
import org.tmatesoft.svn.core.SVNMergeRangeList;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVMergeInfoHandler extends DAVReportHandler {
private static final String MERGEINFO_REPORT = "mergeinfo-report";
private DAVMergeInfoRequest myDAVRequest;
private DAVReportHandler myCommonReportHandler;
public DAVMergeInfoHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
myCommonReportHandler = commonReportHandler;
}
protected DAVRequest getDAVRequest() {
return getMergeInfoRequest();
}
private DAVMergeInfoRequest getMergeInfoRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVMergeInfoRequest();
}
return myDAVRequest;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace(null);
setDAVResource(getRequestedDAVResource(false, false));
String responseBody = generateResponseBody();
try {
setResponseContentLength(responseBody.getBytes(UTF8_ENCODING).length);
} catch (UnsupportedEncodingException e) {
}
write(responseBody);
}
private String generateResponseBody() throws SVNException {
StringBuffer xmlBuffer = new StringBuffer();
addXMLHeader(xmlBuffer, MERGEINFO_REPORT);
for (int i = 0; i < getMergeInfoRequest().getTargetPaths().length; i++) {
String currentPath = getMergeInfoRequest().getTargetPaths()[i];
DAVPathUtil.testCanonical(currentPath);
if (currentPath.length() == 0 || currentPath.charAt(0) != '/') {
getMergeInfoRequest().getTargetPaths()[i] = SVNPathUtil.append(getDAVResource().getResourceURI().getPath(), currentPath);
}
}
//TODO: fixme - add includeDescendants parameter
Map mergeInfoMap = getDAVResource().getRepository().getMergeInfo(getMergeInfoRequest().getTargetPaths(),
getMergeInfoRequest().getRevision(), getMergeInfoRequest().getInherit(), false);
if (mergeInfoMap != null && !mergeInfoMap.isEmpty()) {
for (Iterator iterator = mergeInfoMap.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String path = (String) entry.getKey();
SVNMergeInfo mergeInfo = (SVNMergeInfo) entry.getValue();
addMergeInfo(path, mergeInfo, xmlBuffer);
}
}
addXMLFooter(xmlBuffer, MERGEINFO_REPORT);
return xmlBuffer.toString();
}
private void addMergeInfo(String path, SVNMergeInfo mergeInfo, StringBuffer xmlBuffer) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "mergeinfo-item", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "mergeinfo-path", path, xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "mergeinfo-info", addSourcePathes(mergeInfo), xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "mergeinfo-item", xmlBuffer);
}
private String addSourcePathes(SVNMergeInfo mergeInfo) {
StringBuffer result = new StringBuffer();
for (Iterator iterator = mergeInfo.getMergeSourcesToMergeLists().entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String sourcePath = (String) entry.getKey();
SVNMergeRangeList rangeList = (SVNMergeRangeList) entry.getValue();
result.append(sourcePath);
result.append(":");
result.append(rangeList.toString());
if (iterator.hasNext()) {
result.append('\n');
}
}
return result.toString();
}
}

View File

@@ -0,0 +1,98 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNMergeInfoInheritance;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVMergeInfoRequest extends DAVRequest {
private static final DAVElement INHERIT = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "inherit");
long myRevision = DAVResource.INVALID_REVISION;
SVNMergeInfoInheritance myInherit = SVNMergeInfoInheritance.EXPLICIT;
String[] myTargetPaths = null;
public long getRevision() {
return myRevision;
}
private void setRevision(long revision) {
myRevision = revision;
}
public SVNMergeInfoInheritance getInherit() {
return myInherit;
}
private void setInherit(SVNMergeInfoInheritance inherit) {
myInherit = inherit;
}
public String[] getTargetPaths() {
return myTargetPaths;
}
private void setTargetPaths(String[] targetPaths) {
myTargetPaths = targetPaths;
}
protected void init() throws SVNException {
List children = getRootElement().getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
DAVElementProperty property = (DAVElementProperty) iterator.next();
DAVElement element = property.getName();
if (element == DAVElement.REVISION) {
try {
setRevision(Long.parseLong(property.getFirstValue(true)));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == INHERIT) {
setInherit(parseInheritance(property.getFirstValue(true)));
if (getInherit() == null) {
invalidXML();
}
} else if (element == DAVElement.PATH) {
Collection paths = property.getValues();
String[] targetPaths = new String[paths.size()];
targetPaths = (String[]) paths.toArray(targetPaths);
setTargetPaths(targetPaths);
}
}
}
private SVNMergeInfoInheritance parseInheritance(String inheritance) {
if (SVNMergeInfoInheritance.EXPLICIT.toString().equals(inheritance)) {
return SVNMergeInfoInheritance.EXPLICIT;
} else if (SVNMergeInfoInheritance.INHERITED.toString().equals(inheritance)) {
return SVNMergeInfoInheritance.INHERITED;
} else if (SVNMergeInfoInheritance.NEAREST_ANCESTOR.toString().equals(inheritance)) {
return SVNMergeInfoInheritance.NEAREST_ANCESTOR;
}
return null;
}
}

View File

@@ -0,0 +1,46 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVMergeRequest extends DAVRequest {
private static final DAVElement MERGE = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "merge");
protected void init() throws SVNException {
if (getRoot().getName() != MERGE) {
invalidXMLRoot();
}
}
protected void invalidXMLRoot() throws SVNException {
throw new DAVException("The request body must be present and must be a DAV:merge element.", HttpServletResponse.SC_BAD_REQUEST, 0);
}
protected DAVElementProperty getRoot() throws SVNException {
if (getRootElement() == null) {
invalidXMLRoot();
}
return getRootElement();
}
}

View File

@@ -0,0 +1,268 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceKind;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVOptionsHandler extends ServletDAVHandler {
private static final DAVElement OPTIONS = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "options");
private static final DAVElement ACTIVITY_COLLECTION_SET = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "activity-collection-set");
private static final DAVElement SUPPORTED_METHOD_SET = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "supported-method-set");
private static final DAVElement SUPPORTED_METHOD = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "supported-method");
private static final DAVElement SUPPORTED_LIVE_PROPERTY_SET = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "supported-live-property-set");
private static final DAVElement SUPPORTED_LIVE_PROPERTY = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "supported-live-property");
private static final DAVElement SUPPORTED_REPORT_SET = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "supported-report-set");
private static final DAVElement SUPPORTED_REPORT = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "supported-report");
private static final String DAV_HEADER = "DAV";
private static final String DAV_LEVEL = "1,2";
private static final String VERSION_OPTIONS_FIRST_PART = "version-control,checkout,working-resource";
private static final String VERSION_OPTIONS_SECOND_PART = "merge,baseline,activity,version-controlled-collection";
private static final String MS_AUTHOR_VIA_HEADER = "MS-Author-Via";
private static final String ALLOW_HEADER = "Allow";
private DAVOptionsRequest myDAVRequest;
public DAVOptionsHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
protected DAVRequest getDAVRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVOptionsRequest();
}
return myDAVRequest;
}
private DAVOptionsRequest getOptionsRequest() {
return (DAVOptionsRequest) getDAVRequest();
}
public void execute() throws SVNException {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "in execute() of DAVOptiondsHandler");
readInput(false);
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "read input");
DAVResource resource = getRequestedDAVResource(false, false);
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "got resource");
Collection supportedMethods = getSupportedMethods(resource);
SVNDebugLog.getDefaultLog().logFine(SVNLogType.DEFAULT, "got supported methods");
StringBuffer body = new StringBuffer();
generateOptionsResponse(resource, supportedMethods, body);
String responseBody = body.toString();
try {
setResponseContentLength(responseBody.getBytes(UTF8_ENCODING).length);
} catch (UnsupportedEncodingException e) {
setResponseContentLength(responseBody.getBytes().length);
}
setDefaultResponseHeaders();
setResponseHeaders(supportedMethods);
setResponseContentType(DEFAULT_XML_CONTENT_TYPE);
setResponseStatus(HttpServletResponse.SC_OK);
try {
getResponseWriter().write(responseBody);
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, e), e, SVNLogType.NETWORK);
}
}
protected void startElement(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
if (parent == null && element != OPTIONS) {
invalidXML();
} else if (parent == OPTIONS && element == ACTIVITY_COLLECTION_SET) {
getOptionsRequest().setActivitySetRequest(true);
} else if (parent == SUPPORTED_METHOD_SET && element == SUPPORTED_METHOD) {
String requestedMethodName = attrs.getValue(DAVElement.DAV_NAMESPACE, NAME_ATTR);
if (requestedMethodName == null || getOptionsRequest().getRequestedMethods() == null) {
invalidXML();
}
getOptionsRequest().getRequestedMethods().add(requestedMethodName);
} else if (parent == SUPPORTED_REPORT_SET && element == SUPPORTED_REPORT) {
String requestedReportName = attrs.getValue(DAVElement.DAV_NAMESPACE, NAME_ATTR);
String requestedReportNamespace = attrs.getValue(DAVElement.DAV_NAMESPACE, NAMESPACE_ATTR);
if (requestedReportName == null || getOptionsRequest().getRequestedReports() == null) {
invalidXML();
}
if (requestedReportNamespace == null) {
requestedReportNamespace = DAVElement.SVN_NAMESPACE;
}
getOptionsRequest().getRequestedReports().add(DAVElement.getElement(requestedReportNamespace, requestedReportName));
} else if (parent == SUPPORTED_LIVE_PROPERTY_SET && element == SUPPORTED_LIVE_PROPERTY) {
String requestedLivePropertyName = attrs.getValue(DAVElement.DAV_NAMESPACE, NAME_ATTR);
String requestedLivePropertyNamespace = attrs.getValue(DAVElement.DAV_NAMESPACE, NAMESPACE_ATTR);
if (requestedLivePropertyName == null || getOptionsRequest().getRequestedLiveProperties() == null) {
invalidXML();
}
if (requestedLivePropertyNamespace == null) {
requestedLivePropertyNamespace = DAVElement.DAV_NAMESPACE;
}
getOptionsRequest().getRequestedLiveProperties().add(DAVElement.getElement(requestedLivePropertyNamespace, requestedLivePropertyName));
}
}
protected void endElement(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
}
private static Collection getSupportedMethods(DAVResource resource) throws SVNException {
//TODO: when work with locks will be implemented, we need to check resource state: LOCK_NULL, EXIST, NULL.
Collection supportedMethods = new ArrayList();
supportedMethods.add(DAVHandlerFactory.METHOD_OPTIONS);
if (resource.exists()) {
supportedMethods.add(DAVHandlerFactory.METHOD_GET);
supportedMethods.add(DAVHandlerFactory.METHOD_HEAD);
supportedMethods.add(DAVHandlerFactory.METHOD_POST);
supportedMethods.add(DAVHandlerFactory.METHOD_DELETE);
supportedMethods.add(DAVHandlerFactory.METHOD_TRACE);
supportedMethods.add(DAVHandlerFactory.METHOD_PROPFIND);
supportedMethods.add(DAVHandlerFactory.METHOD_PROPPATCH);
supportedMethods.add(DAVHandlerFactory.METHOD_MOVE);
supportedMethods.add(DAVHandlerFactory.METHOD_COPY);
supportedMethods.add(DAVHandlerFactory.METHOD_LOCK);
supportedMethods.add(DAVHandlerFactory.METHOD_UNLOCK);
if (!resource.isCollection()) {
supportedMethods.add(DAVHandlerFactory.METHOD_PUT);
}
}
//TODO: native svn checks if resource is auto checked out.
if (resource.getResourceURI().getType() == DAVResourceType.ACTIVITY && !resource.exists()) {
supportedMethods.add(DAVHandlerFactory.METHOD_MKACTIVITY);
} else if (resource.getResourceURI().isWorking()) {
supportedMethods.add(DAVHandlerFactory.METHOD_CHECKIN);
} else {
supportedMethods.add(DAVHandlerFactory.METHOD_CHECKOUT);
}
return supportedMethods;
}
private void setResponseHeaders(Collection supportedMethods) {
//MSFT Web Folders chokes if length of DAV header value > 63 characters! (c) Subversion.
setResponseHeader(DAV_HEADER, DAV_LEVEL);
addResponseHeader(DAV_HEADER, VERSION_OPTIONS_FIRST_PART);
addResponseHeader(DAV_HEADER, VERSION_OPTIONS_SECOND_PART);
addResponseHeader(DAV_HEADER, DAVElement.DEPTH_OPTION);
addResponseHeader(DAV_HEADER, DAVElement.LOG_REVPROPS_OPTION);
addResponseHeader(DAV_HEADER, DAVElement.PARTIAL_REPLAY_OPTION);
addResponseHeader(DAV_HEADER, DAVElement.MERGE_INFO_OPTION);
setResponseHeader(MS_AUTHOR_VIA_HEADER, DAV_HEADER);
setResponseHeader(ALLOW_HEADER, generateAllowHeaderValue(supportedMethods));
}
private String generateAllowHeaderValue(Collection supportedMethods) {
StringBuffer allowHeaderBuffer = new StringBuffer();
for (Iterator iterator = supportedMethods.iterator(); iterator.hasNext();) {
allowHeaderBuffer.append(iterator.next());
allowHeaderBuffer.append(iterator.hasNext() ? "," : "");
}
return allowHeaderBuffer.toString();
}
private void generateOptionsResponse(DAVResource resource, Collection supportedMethods, StringBuffer xmlBuffer) throws SVNException {
if (!getOptionsRequest().isEmpty()) {
SVNXMLUtil.addXMLHeader(xmlBuffer);
DAVXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "options-response", null, xmlBuffer, false);
if (getOptionsRequest().isActivitySetRequest()) {
generateActivityCollectionSet(resource, xmlBuffer);
} else if (getOptionsRequest().isSupportedLivePropertiesRequest()) {
generateSupportedLivePropertySet(resource, xmlBuffer);
} else if (getOptionsRequest().isSupportedMethodsRequest()) {
generateSupportedMethodSet(supportedMethods, xmlBuffer);
} else if (getOptionsRequest().isSupportedReportsRequest()) {
generateSupportedReportSet(resource, xmlBuffer);
}
SVNXMLUtil.addXMLFooter(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "options-response", xmlBuffer);
}
}
private void generateActivityCollectionSet(DAVResource resource, StringBuffer xmlBuffer) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "activity-collection-set", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
String uri = DAVPathUtil.buildURI(resource.getResourceURI().getContext(), DAVResourceKind.ACT_COLLECTION, 0, null, false);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "href", uri, xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "activity-collection-set", xmlBuffer);
}
private void generateSupportedLivePropertySet(DAVResource resource, StringBuffer xmlBuffer) throws SVNException {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-live-property-set", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
Collection supportedLiveProperties = getSupportedLiveProperties(resource, null);
generateSupportedElementSet(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-live-property", supportedLiveProperties, getOptionsRequest().getRequestedLiveProperties(), xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-live-property-set", xmlBuffer);
}
private void generateSupportedMethodSet(Collection supportedMethods, StringBuffer xmlBuffer) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-method-set", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
generateSupportedElementSet(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-method", supportedMethods, getOptionsRequest().getRequestedMethods(), xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-method-set", xmlBuffer);
}
private void generateSupportedReportSet(DAVResource resource, StringBuffer xmlBuffer) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-report-set", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
if (resource.getResourceURI().getType() == DAVResourceType.REGULAR) {
generateSupportedElementSet(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-report", REPORT_ELEMENTS, getOptionsRequest().getRequestedReports(), xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "supported-report-set", xmlBuffer);
}
}
private void generateSupportedElementSet(String prefix, String tagName, Collection supportedElements, Collection requestedElements, StringBuffer xmlBuffer) {
for (Iterator iterator = supportedElements.iterator(); iterator.hasNext();) {
Object item = iterator.next();
if (requestedElements.isEmpty() || requestedElements.contains(item)) {
Map attrs = new SVNHashMap();
if (item instanceof DAVElement) {
DAVElement currentElement = (DAVElement) item;
attrs.put(NAME_ATTR, currentElement.getNamespace());
attrs.put(NAMESPACE_ATTR, currentElement.getName());
} else if (item instanceof String) {
String currentName = (String) item;
attrs.put(NAME_ATTR, currentName);
}
SVNXMLUtil.openXMLTag(prefix, tagName, SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, xmlBuffer);
}
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.ArrayList;
import java.util.Collection;
import org.tmatesoft.svn.core.SVNException;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVOptionsRequest extends DAVRequest {
private boolean myIsActivitySetRequest = false;
private Collection myRequestedMethods;
private Collection myRequestedReports;
private Collection myRequestedLiveProperties;
public DAVOptionsRequest() {
super();
}
protected void init() throws SVNException {
}
public boolean isEmpty() {
return !(isActivitySetRequest() || isSupportedLivePropertiesRequest() || isSupportedMethodsRequest() || isSupportedMethodsRequest());
}
public boolean isActivitySetRequest() {
return myIsActivitySetRequest;
}
public void setActivitySetRequest(boolean isActivitySetRequest) {
myIsActivitySetRequest = isActivitySetRequest;
}
public boolean isSupportedMethodsRequest() {
return myRequestedMethods != null;
}
public boolean isSupportedLivePropertiesRequest() {
return myRequestedLiveProperties != null;
}
public boolean isSupportedReportsRequest() {
return myRequestedReports != null;
}
public Collection getRequestedMethods() {
if (myRequestedMethods == null) {
myRequestedMethods = new ArrayList();
}
return myRequestedMethods;
}
public Collection getRequestedLiveProperties() {
if (myRequestedLiveProperties == null) {
myRequestedLiveProperties = new ArrayList();
}
return myRequestedLiveProperties;
}
public Collection getRequestedReports() {
if (myRequestedReports == null) {
myRequestedReports = new ArrayList();
}
return myRequestedReports;
}
}

View File

@@ -0,0 +1,355 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVErrorCode;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVPropPatchHandler extends ServletDAVHandler {
private DAVPropPatchRequest myDAVRequest;
protected DAVPropPatchHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
public void execute() throws SVNException {
DAVResource resource = getRequestedDAVResource(false, false);
if (!resource.exists()) {
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
long readLength = readInput(false);
if (readLength <= 0) {
getPropPatchRequest().invalidXMLRoot();
}
validateRequest(resource, DAVDepth.DEPTH_ZERO, DAV_VALIDATE_RESOURCE, null, null, null);
DAVAutoVersionInfo avInfo = autoCheckOut(resource, false);
DAVPropertiesProvider propsProvider = null;
try {
propsProvider = DAVPropertiesProvider.createPropertiesProvider(resource, this);
} catch (DAVException dave) {
autoCheckIn(resource, true, false, avInfo);
throw new DAVException("Could not open the property database for {0}.", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) },
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
boolean isFailure = false;
List properties = new LinkedList();
DAVPropPatchRequest requestXMLObject = getPropPatchRequest();
DAVElementProperty rootElement = requestXMLObject.getRoot();
List childrenElements = rootElement.getChildren();
for (Iterator childrenIter = childrenElements.iterator(); childrenIter.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) childrenIter.next();
DAVElement childElementName = childElement.getName();
if (!DAVElement.DAV_NAMESPACE.equals(childElementName.getNamespace()) || (childElementName != DAVPropPatchRequest.REMOVE &&
childElementName != DAVPropPatchRequest.SET)) {
continue;
}
DAVElementProperty propChildrenElement = childElement.getChild(DAVElement.PROP);
if (propChildrenElement == null) {
autoCheckIn(resource, true, false, avInfo);
SVNDebugLog.getDefaultLog().logError(SVNLogType.NETWORK, "A \"prop\" element is missing inside the propertyupdate command.");
setResponseStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
boolean isRemove = childElementName == DAVPropPatchRequest.REMOVE;
List propChildren = propChildrenElement.getChildren();
for (Iterator propsIter = propChildren.iterator(); propsIter.hasNext();) {
DAVElementProperty property = (DAVElementProperty) propsIter.next();
DAVElement propertyName = property.getName();
PropertyChangeContext propContext = new PropertyChangeContext();
propContext.myIsSet = !isRemove;
propContext.myProperty = property;
properties.add(propContext);
validateProp(propertyName, propsProvider, propContext);
if (propContext.myError != null && propContext.myError.getResponseCode() >= 300) {
isFailure = true;
}
}
}
String propStatText = null;
DAVPropertyExecuteHandler executeHandler = new DAVPropertyExecuteHandler(propsProvider);
if (!isFailure && processPropertyContextList(executeHandler, properties, true, false)) {
isFailure = true;
}
if (isFailure) {
DAVPropertyRollBackHandler rollBackHandler = new DAVPropertyRollBackHandler(propsProvider);
processPropertyContextList(rollBackHandler, properties, false, true);
propStatText = getFailureMessage(properties);
} else {
propStatText = getSuccessMessage(properties);
}
autoCheckIn(resource, isFailure, false, avInfo);
//TODO: log propCtxt.error here later
DAVPropsResult propResult = new DAVPropsResult();
propResult.addPropStatsText(propStatText);
DAVResponse response = new DAVResponse(null, resource.getResourceURI().getRequestURI(), null, propResult, 0);
try {
DAVXMLUtil.sendMultiStatus(response, getHttpServletResponse(), SC_MULTISTATUS, getNamespaces());
} catch (IOException ioe) {
throw new DAVException(ioe.getMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, SVNErrorCode.IO_ERROR.getCode());
}
}
private String getFailureMessage(List propContextList) {
DAVException err424Set = null;
DAVException err424Delete = null;
StringBuffer buffer = new StringBuffer();
for (Iterator propsIter = propContextList.iterator(); propsIter.hasNext();) {
PropertyChangeContext propContext = (PropertyChangeContext) propsIter.next();
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
DAVXMLUtil.addEmptyElement(getNamespaces(), propContext.myProperty.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), buffer);
if (propContext.myError == null) {
if (propContext.myIsSet) {
if (err424Set == null) {
err424Set = new DAVException("Attempted DAV:set operation could not be completed due to other errors.",
SC_FAILED_DEPENDANCY, 0);
}
propContext.myError = err424Set;
} else {
if (err424Delete == null) {
err424Delete = new DAVException("Attempted DAV:remove operation could not be completed due to other errors.",
SC_FAILED_DEPENDANCY, 0);
}
propContext.myError = err424Delete;
}
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append("HTTP/1.1 ");
buffer.append(propContext.myError.getResponseCode());
buffer.append(" (status)");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), buffer);
if (propContext.myError.getMessage() != null) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE_DESCRIPTION.getName(),
SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
buffer.append(propContext);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.RESPONSE_DESCRIPTION.getName(), buffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), buffer);
}
return buffer.toString();
}
private String getSuccessMessage(List propContextList) {
StringBuffer buffer = new StringBuffer();
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
for (Iterator propsIter = propContextList.iterator(); propsIter.hasNext();) {
PropertyChangeContext propContext = (PropertyChangeContext) propsIter.next();
DAVXMLUtil.addEmptyElement(getNamespaces(), propContext.myProperty.getName(), buffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append("HTTP/1.1 200 OK");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), buffer);
return buffer.toString();
}
private boolean processPropertyContextList(IDAVPropertyContextHandler handler, List propertyContextList, boolean stopOnError, boolean reverse) {
ListIterator propContextIterator = propertyContextList.listIterator(reverse ? propertyContextList.size() : 0);
for (; reverse ? propContextIterator.hasPrevious() : propContextIterator.hasNext();) {
PropertyChangeContext propContext = (PropertyChangeContext) (reverse ? propContextIterator.previous() : propContextIterator.next());
handler.handleContext(propContext);
if (stopOnError && propContext.myError != null && propContext.myError.getResponseCode() >= 300) {
return true;
}
}
return false;
}
private void validateProp(DAVElement property, DAVPropertiesProvider propsProvider,
PropertyChangeContext propContext) {
LivePropertySpecification livePropSpec = findLiveProperty(property);
propContext.myLivePropertySpec = livePropSpec;
if (!isPropertyWritable(property, livePropSpec)) {
propContext.myError = new DAVException("Property is read-only.", HttpServletResponse.SC_CONFLICT, DAVErrorCode.PROP_READONLY);
return;
}
if (livePropSpec != null && livePropSpec.isSVNSupported()) {
return;
}
if (propsProvider.isDeferred()) {
try {
propsProvider.open(false);
} catch (DAVException dave) {
propContext.myError = dave;
return;
}
}
if (!propsProvider.isOperative()) {
propContext.myError = new DAVException("Attempted to set/remove a property without a valid, open, read/write property database.",
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DAVErrorCode.PROP_NO_DATABASE);
return;
}
}
protected DAVRequest getDAVRequest() {
return getPropPatchRequest();
}
private boolean isPropertyWritable(DAVElement property, LivePropertySpecification livePropSpec) {
if (livePropSpec != null) {
return livePropSpec.isWritable();
}
if (property == DAVElement.LOCK_DISCOVERY || property == DAVElement.SUPPORTED_LOCK) {
return false;
}
return true;
}
private DAVPropPatchRequest getPropPatchRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVPropPatchRequest();
}
return myDAVRequest;
}
private static class PropertyChangeContext {
private boolean myIsSet;
private DAVElementProperty myProperty;
private LivePropertySpecification myLivePropertySpec;
private DAVException myError;
private RollBackProperty myRollBackProperty;
}
private static class RollBackProperty {
private DAVElement myPropertyName;
private SVNPropertyValue myRollBackPropertyValue;
public RollBackProperty(DAVElement propertyName, SVNPropertyValue rollBackPropertyValue) {
myPropertyName = propertyName;
myRollBackPropertyValue = rollBackPropertyValue;
}
}
private static interface IDAVPropertyContextHandler {
public void handleContext(PropertyChangeContext propContext);
}
private class DAVPropertyExecuteHandler implements IDAVPropertyContextHandler {
private DAVPropertiesProvider myPropsProvider;
public DAVPropertyExecuteHandler(DAVPropertiesProvider propsProvider) {
myPropsProvider = propsProvider;
}
public void handleContext(PropertyChangeContext propContext) {
if (propContext.myLivePropertySpec == null) {
try {
SVNPropertyValue rollBackPropValue = myPropsProvider.getPropertyValue(propContext.myProperty.getName());
propContext.myRollBackProperty = new RollBackProperty(propContext.myProperty.getName(), rollBackPropValue);
} catch (DAVException dave) {
handleError(dave, propContext);
return;
}
if (propContext.myIsSet) {
try {
myPropsProvider.storeProperty(propContext.myProperty);
} catch (DAVException dave) {
handleError(dave, propContext);
return;
}
} else {
try {
myPropsProvider.removeProperty(propContext.myProperty.getName());
} catch (DAVException dave) {
//
}
}
}
}
private void handleError(DAVException dave, PropertyChangeContext propContext) {
DAVException exc = new DAVException("Could not execute PROPPATCH.", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, dave,
DAVErrorCode.PROP_EXEC);
propContext.myError = exc;
}
}
private class DAVPropertyRollBackHandler implements IDAVPropertyContextHandler {
private DAVPropertiesProvider myPropsProvider;
public DAVPropertyRollBackHandler(DAVPropertiesProvider propsProvider) {
myPropsProvider = propsProvider;
}
public void handleContext(PropertyChangeContext propContext) {
if (propContext.myRollBackProperty == null) {
return;
}
if (propContext.myLivePropertySpec == null) {
try {
myPropsProvider.applyRollBack(propContext.myRollBackProperty.myPropertyName,
propContext.myRollBackProperty.myRollBackPropertyValue);
} catch (DAVException dave) {
if (propContext.myError == null) {
propContext.myError = dave;
} else {
DAVException err = dave;
while (err.getPreviousException() != null) {
err = err.getPreviousException();
}
err.setPreviousException(propContext.myError);
propContext.myError = dave;
}
}
}
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVPropPatchRequest extends DAVRequest {
private static final DAVElement PROPERTY_UPDATE = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "propertyupdate");
public static final DAVElement REMOVE = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "remove");
public static final DAVElement SET = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "set");
protected void init() throws SVNException {
if (getRoot().getName() != PROPERTY_UPDATE) {
invalidXMLRoot();
}
}
protected void invalidXMLRoot() throws SVNException {
throw new DAVException("The request body does not contain a \"propertyupdate\" element.", null, HttpServletResponse.SC_BAD_REQUEST,
null, SVNLogType.NETWORK, Level.FINE, null, null, null, 0, null);
}
protected DAVElementProperty getRoot() throws SVNException {
if (getRootElement() == null) {
invalidXMLRoot();
}
return getRootElement();
}
}

View File

@@ -0,0 +1,368 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSCommitter;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionNode;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.server.dav.DAVConfig;
import org.tmatesoft.svn.core.internal.server.dav.DAVErrorCode;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceURI;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVPropertiesProvider {
private boolean myIsDeferred;
private boolean myIsOperative;
private DAVResource myResource;
private ServletDAVHandler myOwner;
private SVNProperties myProperties;
private DAVPropertiesProvider(boolean isDeferred, ServletDAVHandler owner, DAVResource resource) {
myIsDeferred = isDeferred;
myOwner = owner;
myResource = resource;
}
public static DAVPropertiesProvider createPropertiesProvider(DAVResource resource, ServletDAVHandler owner) throws DAVException {
DAVResourceURI resourceURI = resource.getResourceURI();
if (resourceURI.getURI() == null) {
throw new DAVException("INTERNAL DESIGN ERROR: resource must define its URI.", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
DAVPropertiesProvider provider = new DAVPropertiesProvider(true, owner, resource);
return provider;
}
public void open(boolean readOnly) throws DAVException {
myIsDeferred = false;
try {
doOpen(readOnly);
} catch (DAVException dave) {
throw new DAVException("Could not open the property database.", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DAVErrorCode.PROP_OPENING);
}
}
public void applyRollBack(DAVElement propName, SVNPropertyValue propValue) throws DAVException {
if (propValue == null) {
removeProperty(propName);
return;
}
saveValue(propName, propValue);
}
public void removeProperty(DAVElement propName) throws DAVException {
String reposPropName = getReposPropName(propName);
if (reposPropName == null) {
return;
}
try {
FSFS fsfs = myResource.getFSFS();
if (myResource.isBaseLined()) {
if (myResource.isWorking()) {
FSTransactionInfo txn = myResource.getTxnInfo();
SVNProperties props = new SVNProperties();
props.put(reposPropName, (SVNPropertyValue) null);
fsfs.changeTransactionProperties(txn.getTxnId(), props);
} else {
SVNRepository repos = myResource.getRepository();
repos.setRevisionPropertyValue(myResource.getRevision(), reposPropName, null);
}
} else {
DAVResourceURI resourceURI = myResource.getResourceURI();
FSCommitter committer = getCommitter();
committer.changeNodeProperty(resourceURI.getPath(), reposPropName, null);
}
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "could not remove a property", null);
}
myProperties = null;
}
public void storeProperty(DAVElementProperty property) throws DAVException {
DAVElement propName = property.getName();
String propValue = property.getFirstValue(false);
String reposPropName = getReposPropName(propName);
SVNPropertyValue value = null;
Map attributes = property.getAttributes();
if (attributes != null) {
for (Iterator attrsIter = attributes.keySet().iterator(); attrsIter.hasNext();) {
String attrName = (String) attrsIter.next();
if (ServletDAVHandler.ENCODING_ATTR.equals(attrName)) {
String encodingType = (String) attributes.get(attrName);
if (ServletDAVHandler.BASE64_ENCODING.equals(encodingType)) {
byte[] buffer = new byte[propValue.length()];
int length = SVNBase64.base64ToByteArray(new StringBuffer(propValue), buffer);
value = SVNPropertyValue.create(reposPropName, buffer, 0, length);
} else {
throw new DAVException("Unknown property encoding", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 0);
}
break;
}
}
}
if (value == null) {
value = SVNPropertyValue.create(propValue);
}
saveValue(propName, value);
}
public void defineNamespaces(Map namespaces) {
namespaces.put(DAVElement.SVN_SVN_PROPERTY_NAMESPACE, "S");
namespaces.put(DAVElement.SVN_CUSTOM_PROPERTY_NAMESPACE, "C");
namespaces.put(DAVElement.SVN_DAV_PROPERTY_NAMESPACE, "V");
}
/**
* @return Collection of DAVElement objects
*/
public Collection getPropertyNames() throws DAVException {
FSFS fsfs = myResource.getFSFS();
SVNException exc = null;
if (myProperties == null) {
if (myResource.isBaseLined()) {
if (myResource.getType() == DAVResourceType.WORKING) {
try {
myProperties = fsfs.getTransactionProperties(myResource.getTxnName());
} catch (SVNException svne) {
exc = svne;
}
} else {
try {
myProperties = fsfs.getRevisionProperties(myResource.getRevision());
} catch (SVNException svne) {
exc = svne;
}
}
} else {
FSRoot root = myResource.getRoot();
String path = myResource.getResourceURI().getPath();
try {
FSRevisionNode node = root.getRevisionNode(path);
myProperties = node.getProperties(fsfs);
} catch (SVNException svne) {
exc = svne;
}
if (exc == null) {
try {
root.checkNodeKind(path);
} catch (SVNException svne) {
exc = svne;
}
//TODO: add logging here?
}
}
if (exc != null) {
throw DAVException.convertError(exc.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not begin sequencing through properties", null);
}
}
Collection propNames = new ArrayList();
for (Iterator namesIter = myProperties.nameSet().iterator(); namesIter.hasNext();) {
String propName = (String) namesIter.next();
DAVElement propElementName = null;
if (propName.startsWith(SVNProperty.SVN_PREFIX)) {
propElementName = DAVElement.getElement(DAVElement.SVN_SVN_PROPERTY_NAMESPACE,
propName.substring(SVNProperty.SVN_PREFIX.length()));
} else {
propElementName = DAVElement.getElement(DAVElement.SVN_CUSTOM_PROPERTY_NAMESPACE, propName);
}
propNames.add(propElementName);
}
return propNames;
}
public boolean outputValue(DAVElement propName, StringBuffer buffer) throws DAVException {
SVNPropertyValue propValue = getPropertyValue(propName);
boolean found = propValue != null;
if (!found) {
return found;
}
String prefix = null;
if (DAVElement.SVN_CUSTOM_PROPERTY_NAMESPACE.equals(propName.getNamespace())) {
prefix = "C";
} else {
prefix = "S";
}
String propValueString = SVNPropertyValue.getPropertyAsString(propValue);
if ("".equals(propValueString)) {
SVNXMLUtil.openXMLTag(prefix, propName.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, buffer);
} else {
String xmlSafeValue = null;
Map attrs = null;
if (!SVNEncodingUtil.isXMLSafe(propValueString)) {
try {
xmlSafeValue = SVNBase64.byteArrayToBase64(propValueString.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
xmlSafeValue = SVNBase64.byteArrayToBase64(propValueString.getBytes());
}
attrs = new HashMap();
attrs.put("V:encoding", "base64");
} else {
xmlSafeValue = SVNEncodingUtil.xmlEncodeCDATA(propValueString);
}
SVNXMLUtil.openXMLTag(prefix, propName.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, attrs, buffer);
buffer.append(xmlSafeValue);
SVNXMLUtil.closeXMLTag(prefix, propName.getName(), buffer);
}
return found;
}
public SVNPropertyValue getPropertyValue(DAVElement propName) throws DAVException {
String reposPropName = getReposPropName(propName);
if (reposPropName == null) {
return null;
}
SVNProperties props = null;
FSFS fsfs = myResource.getFSFS();
try {
//TODO: if myProperties != null, try searching there first
if (myResource.isBaseLined()) {
if (myResource.getType() == DAVResourceType.WORKING) {
FSTransactionInfo txn = myResource.getTxnInfo();
props = fsfs.getTransactionProperties(txn.getTxnId());
} else {
long revision = myResource.getRevision();
props = fsfs.getRevisionProperties(revision);
}
} else {
FSRoot root = myResource.getRoot();
props = fsfs.getProperties(root.getRevisionNode(myResource.getResourceURI().getPath()));
}
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not fetch a property", null);
}
if (props != null) {
return props.getSVNPropertyValue(reposPropName);
}
return null;
}
public DAVResource getResource() {
return myResource;
}
private void saveValue(DAVElement propName, SVNPropertyValue value) throws DAVException {
String reposPropName = getReposPropName(propName);
if (reposPropName == null) {
DAVConfig config = myResource.getRepositoryManager().getDAVConfig();
if (config.isAutoVersioning()) {
reposPropName = propName.getName();
} else {
throw new DAVException("Properties may only be defined in the {0} and {1} namespaces.",
new Object[] { DAVElement.SVN_SVN_PROPERTY_NAMESPACE, DAVElement.SVN_CUSTOM_PROPERTY_NAMESPACE },
HttpServletResponse.SC_CONFLICT, 0);
}
}
try {
FSFS fsfs = myResource.getFSFS();
if (myResource.isBaseLined()) {
if (myResource.isWorking()) {
FSTransactionInfo txn = myResource.getTxnInfo();
SVNProperties props = new SVNProperties();
props.put(reposPropName, value);
fsfs.changeTransactionProperties(txn.getTxnId(), props);
} else {
SVNRepository repos = myResource.getRepository();
repos.setRevisionPropertyValue(myResource.getRevision(), reposPropName, value);
//TODO: maybe add logging here
}
} else {
DAVResourceURI resourceURI = myResource.getResourceURI();
FSCommitter committer = getCommitter();
committer.changeNodeProperty(resourceURI.getPath(), reposPropName, value);
}
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, null);
}
myProperties = null;
}
private String getReposPropName(DAVElement propName) {
if (DAVElement.SVN_SVN_PROPERTY_NAMESPACE.equals(propName.getNamespace())) {
return SVNProperty.SVN_PREFIX + propName.getName();
} else if (DAVElement.SVN_CUSTOM_PROPERTY_NAMESPACE.equals(propName.getNamespace())) {
return propName.getName();
}
return null;
}
public boolean isOperative() {
return myIsOperative;
}
public boolean isDeferred() {
return myIsDeferred;
}
public void setDeferred(boolean isDeferred) {
myIsDeferred = isDeferred;
}
private void doOpen(boolean readOnly) throws DAVException {
myIsOperative = true;
DAVResourceType resType = myResource.getType();
if (resType == DAVResourceType.HISTORY || resType == DAVResourceType.ACTIVITY || resType == DAVResourceType.PRIVATE) {
myIsOperative = false;
return;
}
if (!readOnly && resType != DAVResourceType.WORKING) {
if (!(myResource.isBaseLined() && resType == DAVResourceType.VERSION)) {
throw new DAVException("Properties may only be changed on working resources.", HttpServletResponse.SC_CONFLICT, 0);
}
}
}
private FSCommitter getCommitter() {
return myOwner.getCommitter(myResource.getFSFS(), myResource.getRoot(), myResource.getTxnInfo(), myResource.getLockTokens(),
myResource.getUserName());
}
}

View File

@@ -0,0 +1,803 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionRoot;
import org.tmatesoft.svn.core.internal.server.dav.DAVConfig;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceKind;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceState;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceURI;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import org.tmatesoft.svn.core.internal.server.dav.DAVServletUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNPropertiesManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVPropfindHandler extends ServletDAVHandler implements IDAVResourceWalkHandler {
public static final List NAMESPACES = new LinkedList();
static {
NAMESPACES.add(DAVElement.DAV_NAMESPACE);
NAMESPACES.add(DAVElement.SVN_DAV_PROPERTY_NAMESPACE);
}
private static final String DEFAULT_AUTOVERSION_LINE = "DAV:checkout-checkin";
private DAVPropfindRequest myDAVRequest;
private boolean myIsAllProp;
//private boolean myIsPropName;
private boolean myIsProp;
private DAVElementProperty myDocRoot;
private StringBuffer myPropStat404;
private StringBuffer myResponseBuffer;
private DAVLockInfoProvider myLocksProvider;
public DAVPropfindHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
protected DAVRequest getDAVRequest() {
return getPropfindRequest();
}
public void execute() throws SVNException {
DAVResource resource = getRequestedDAVResource(true, false);
DAVResourceState resourceState = getResourceState(resource);
if (resourceState == DAVResourceState.NULL) {
//TODO: what body should we send?
sendError(HttpServletResponse.SC_NOT_FOUND, null);
return;
}
DAVDepth depth = getRequestDepth(DAVDepth.DEPTH_INFINITY);
//TODO: check the depth is not less than 0; if it is, send BAD_REQUEST
if (depth == DAVDepth.DEPTH_INFINITY && resource.isCollection()) {
DAVConfig config = getConfig();
if (!config.isAllowDepthInfinity()) {
String message = "PROPFIND requests with a Depth of \"infinity\" are not allowed for " +
SVNEncodingUtil.xmlEncodeCDATA(getURI()) + ".";
response(message, DAVServlet.getStatusLine(HttpServletResponse.SC_FORBIDDEN), HttpServletResponse.SC_FORBIDDEN);
return;
}
}
long readCount = readInput(false);
DAVPropfindRequest request = getPropfindRequest();
DAVElementProperty rootElement = request.getRootElement();
if (readCount > 0 && rootElement.getName() != DAVElement.PROPFIND) {
//TODO: maybe add logging here later
//TODO: what body should we send?
sendError(HttpServletResponse.SC_BAD_REQUEST, null);
return;
}
myIsAllProp = false;
//myIsPropName = false;
myIsProp = false;
if (readCount == 0 || rootElement.hasChild(DAVElement.ALLPROP)) {
myIsAllProp = true;
} else if (rootElement.hasChild(DAVElement.PROPNAME)) {
//myIsPropName = true;
} else if (rootElement.hasChild(DAVElement.PROP)) {
myIsProp = true;
} else {
//TODO: what body should we send?
//TODO: maybe add logging here later
setResponseStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
myLocksProvider = null;
try {
myLocksProvider = DAVLockInfoProvider.createLockInfoProvider(this, false);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"The lock database could not be opened, preventing access to the various lock properties for the PROPFIND.", null);
}
myResponseBuffer = new StringBuffer();
DAVXMLUtil.beginMultiStatus(getHttpServletResponse(), SC_MULTISTATUS, getNamespaces(), myResponseBuffer);
int walkType = DAVResourceWalker.DAV_WALKTYPE_NORMAL | DAVResourceWalker.DAV_WALKTYPE_AUTH | DAVResourceWalker.DAV_WALKTYPE_LOCKNULL;
DAVResourceWalker walker = new DAVResourceWalker();
DAVException error = null;
try {
walker.walk(myLocksProvider, resource, null, 0, null, walkType, this, depth);
} catch (DAVException dave) {
error = dave;
}
if (error != null) {
throw new DAVException("Provider encountered an error while streaming", error.getResponseCode(), error, 0);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.MULTISTATUS.getName(), myResponseBuffer);
String responseBody = myResponseBuffer.toString();
try {
setResponseContentLength(responseBody.getBytes(UTF8_ENCODING).length);
} catch (UnsupportedEncodingException e) {
setResponseContentLength(responseBody.getBytes().length);
}
setResponseStatus(SC_MULTISTATUS);
try {
getResponseWriter().write(responseBody);
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, e), e, SVNLogType.NETWORK);
}
}
public DAVResponse handleResource(DAVResponse response, DAVResource resource, DAVLockInfoProvider lockInfoProvider, LinkedList ifHeaders,
int flags, DAVLockScope lockScope, CallType callType) throws DAVException {
DAVPropertiesProvider propsProvider = null;
try {
propsProvider = DAVPropertiesProvider.createPropertiesProvider(resource, this);
} catch (DAVException dave) {
if (myIsProp) {
cacheBadProps();
DAVPropsResult badProps = new DAVPropsResult();
badProps.addPropStatsText(myPropStat404.toString());
streamResponse(resource, 0, badProps);
} else {
streamResponse(resource, HttpServletResponse.SC_OK, null);
}
return null;
}
DAVPropsResult result = null;
if (myIsProp) {
result = getProps(propsProvider, getPropfindRequest().getRootElement());
} else {
DAVInsertPropAction action = myIsAllProp ? DAVInsertPropAction.INSERT_VALUE : DAVInsertPropAction.INSERT_NAME;
result = getAllProps(propsProvider, action);
}
streamResponse(resource, 0, result);
return null;
}
private DAVPropsResult getAllProps(DAVPropertiesProvider propsProvider, DAVInsertPropAction action) throws DAVException {
boolean foundContentType = false;
boolean foundContentLang = false;
DAVPropsResult result = new DAVPropsResult();
StringBuffer buffer = new StringBuffer();
if (action != DAVInsertPropAction.INSERT_SUPPORTED) {
if (propsProvider.isDeferred()) {
propsProvider.open(true);
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
Map namespacesToPrefixes = new HashMap();
propsProvider.defineNamespaces(namespacesToPrefixes);
Collection propNames = propsProvider.getPropertyNames();
int ind = 0;
for (Iterator propNamesIter = propNames.iterator(); propNamesIter.hasNext();) {
DAVElement propNameElement = (DAVElement) propNamesIter.next();
if (DAVElement.DAV_NAMESPACE.equals(propNameElement.getNamespace())) {
if (DAVElement.GET_CONTENT_TYPE.getName().equals(propNameElement.getName())) {
foundContentType = true;
} else if (DAVElement.GET_CONTENT_LANGUAGE.getName().equals(propNameElement.getName())) {
foundContentLang = true;
}
}
if (action == DAVInsertPropAction.INSERT_VALUE) {
try {
propsProvider.outputValue(propNameElement, buffer);
} catch (DAVException dave) {
//TODO: probably change this behavior in future
continue;
}
} else {
ind = outputPropName(propNameElement, namespacesToPrefixes, ind, buffer);
}
}
generateXMLNSNamespaces(result, namespacesToPrefixes);
}
addAllLivePropNamespaces(result);
insertAllLiveProps(propsProvider.getResource(), action, buffer);
LivePropertySpecification suppLockSpec = (LivePropertySpecification) OUR_CORE_LIVE_PROPS.get(DAVElement.SUPPORTED_LOCK);
insertCoreLiveProperty(propsProvider.getResource(), action, suppLockSpec, buffer);
LivePropertySpecification lockDiscoverySpec = (LivePropertySpecification) OUR_CORE_LIVE_PROPS.get(DAVElement.LOCK_DISCOVERY);
insertCoreLiveProperty(propsProvider.getResource(), action, lockDiscoverySpec, buffer);
if (!foundContentType) {
LivePropertySpecification getContentTypeSpec = (LivePropertySpecification) OUR_CORE_LIVE_PROPS.get(DAVElement.GET_CONTENT_TYPE);
insertCoreLiveProperty(propsProvider.getResource(), action, getContentTypeSpec, buffer);
}
if (!foundContentLang) {
LivePropertySpecification getContentLanguageSpec = (LivePropertySpecification) OUR_CORE_LIVE_PROPS.get(DAVElement.GET_CONTENT_LANGUAGE);
insertCoreLiveProperty(propsProvider.getResource(), action, getContentLanguageSpec, buffer);
}
if (action != DAVInsertPropAction.INSERT_SUPPORTED) {
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), buffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), "HTTP/1.1 200 OK", null, false, false, buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), buffer);
}
result.addPropStatsText(buffer.toString());
return result;
}
private void insertAllLiveProps(DAVResource resource, DAVInsertPropAction propAction, StringBuffer buffer) throws DAVException {
if (!resource.exists()) {
return;
}
for (Iterator livePropsIter = OUR_LIVE_PROPS.keySet().iterator(); livePropsIter.hasNext();) {
DAVElement propElement = (DAVElement) livePropsIter.next();
if (propElement == DAVElement.COMMENT || propElement == DAVElement.DISPLAY_NAME || propElement == DAVElement.SOURCE) {
//only RESOURCETYPE core prop should be inserted
continue;
}
LivePropertySpecification lps = (LivePropertySpecification) OUR_LIVE_PROPS.get(propElement);
insertLiveProp(resource, lps, propAction, buffer);
}
}
private DAVPropsResult getProps(DAVPropertiesProvider propsProvider, DAVElementProperty docRootElement) throws DAVException {
StringBuffer buffer = new StringBuffer();
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, buffer);
StringBuffer badRes = null;
Collection xmlnses = new LinkedList();
boolean haveGood = false;
boolean definedNamespaces = false;
Map namespacesToPrefixes = new HashMap();
int prefixInd = 0;
DAVElementProperty propElement = docRootElement.getChild(DAVElement.PROP);
List childrenElements = propElement.getChildren();
boolean filledNamespaces = false;
for (Iterator childrenIter = childrenElements.iterator(); childrenIter.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) childrenIter.next();
LivePropertySpecification livePropSpec = findLiveProperty(childElement.getName());
if (livePropSpec != null) {
DAVInsertPropAction doneAction = insertLiveProp(propsProvider.getResource(), livePropSpec,
DAVInsertPropAction.INSERT_VALUE, buffer);
if (doneAction == DAVInsertPropAction.INSERT_VALUE) {
haveGood = true;
if (!filledNamespaces) {
int ind = 0;
for (Iterator namespacesIter = NAMESPACES.iterator(); namespacesIter.hasNext();) {
String namespace = (String) namespacesIter.next();
String xmlns = " xmlns:lp" + ind + "=\"" + namespace + "\"";
xmlnses.add(xmlns);
ind++;
}
filledNamespaces = true;
}
continue;
}
}
if (propsProvider.isDeferred()) {
propsProvider.open(true);
}
boolean found = false;
try {
found = propsProvider.outputValue(childElement.getName(), buffer);
} catch (DAVException dave) {
continue;
}
if (found) {
haveGood = true;
if (!definedNamespaces) {
propsProvider.defineNamespaces(namespacesToPrefixes);
definedNamespaces = true;
}
continue;
}
if (badRes == null) {
badRes = new StringBuffer();
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, badRes);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, badRes);
}
prefixInd = outputPropName(childElement.getName(), namespacesToPrefixes, prefixInd, buffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), buffer);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, buffer);
buffer.append("HTTP/1.1 200 OK");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), buffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), buffer);
DAVPropsResult result = new DAVPropsResult();
if (badRes != null) {
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), badRes);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, badRes);
badRes.append("HTTP/1.1 404 Not Found");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), badRes);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), badRes);
if (!haveGood) {
result.addPropStatsText(badRes.toString());
} else {
result.addPropStatsText(buffer.toString());
result.addPropStatsText(badRes.toString());
}
} else {
result.addPropStatsText(buffer.toString());
}
addNamespaces(result, xmlnses);
generateXMLNSNamespaces(result, namespacesToPrefixes);
return result;
}
private void addNamespaces(DAVPropsResult result, Collection xmlnses) {
for (Iterator xmlnsesIter = xmlnses.iterator(); xmlnsesIter.hasNext();) {
String xmlnsString = (String) xmlnsesIter.next();
result.addNamespace(xmlnsString);
}
}
private void addAllLivePropNamespaces(DAVPropsResult result) {
for (Iterator namespacesIter = NAMESPACES.iterator(); namespacesIter.hasNext();) {
String namespace = (String) namespacesIter.next();
int ind = NAMESPACES.indexOf(namespace);
String xmlnsStr = " xmlns:lp" + ind + "=\"" + namespace + "\"";
result.addNamespace(xmlnsStr);
}
}
private void generateXMLNSNamespaces(DAVPropsResult result, Map namespacesToPrefixes) {
for (Iterator prefixesIter = namespacesToPrefixes.keySet().iterator(); prefixesIter.hasNext();) {
String uri = (String) prefixesIter.next();
String prefix = (String) namespacesToPrefixes.get(uri);
result.addNamespace(" xmlns:" + prefix + "=\"" + uri + "\"");
}
}
private int outputPropName(DAVElement propName, Map namespacesToPrefixes, int ind, StringBuffer buffer) {
if ("".equals(propName.getNamespace())) {
SVNXMLUtil.openXMLTag(null, propName.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, buffer);
} else {
String prefix = namespacesToPrefixes != null ? (String) namespacesToPrefixes.get(propName.getNamespace()) : null;
if (prefix == null) {
prefix = "g" + ind;
namespacesToPrefixes.put(propName.getNamespace(), prefix);
}
SVNXMLUtil.openXMLTag((String) namespacesToPrefixes.get(propName.getNamespace()), propName.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, buffer);
}
return ++ind;
}
private DAVInsertPropAction insertCoreLiveProperty(DAVResource resource, DAVInsertPropAction propAction,
LivePropertySpecification livePropSpec, StringBuffer buffer) throws DAVException {
DAVInsertPropAction inserted = DAVInsertPropAction.NOT_DEF;
DAVElement livePropElement = livePropSpec.getPropertyName();
String value = null;
if (livePropElement == DAVElement.LOCK_DISCOVERY) {
if (myLocksProvider != null) {
DAVLock lock = null;
try {
lock = myLocksProvider.getLock(resource);
} catch (DAVException dave) {
throw new DAVException("DAV:lockdiscovery could not be determined due to a problem fetching the locks for this resource.",
dave.getResponseCode(), dave, 0);
}
if (lock == null) {
value = "";
} else {
value = DAVLockInfoProvider.getActiveLockXML(lock);
}
}
} else if (livePropElement == DAVElement.SUPPORTED_LOCK) {
if (myLocksProvider != null) {
value = myLocksProvider.getSupportedLock(resource);
}
} else if (livePropElement == DAVElement.GET_CONTENT_TYPE) {
//TODO: get content type from a response when imitating a GET request?
} else if (livePropElement == DAVElement.GET_CONTENT_LANGUAGE) {
//TODO: get Content-Language from a response when imitating a GET request?
}
if (value != null) {
if (propAction == DAVInsertPropAction.INSERT_SUPPORTED) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.SUPPORTED_LIVE_PROPERTY.getName(), SVNXMLUtil.XML_STYLE_NORMAL,
"D:name", livePropElement.getName(), buffer);
} else if (propAction == DAVInsertPropAction.INSERT_VALUE && !"".equals(value)) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, livePropElement.getName(), value, null, false, false, buffer);
} else {
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, livePropElement.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, buffer);
}
inserted = propAction;
}
return inserted;
}
private DAVInsertPropAction insertLiveProp(DAVResource resource, LivePropertySpecification livePropSpec, DAVInsertPropAction propAction,
StringBuffer buffer) throws DAVException {
if (!livePropSpec.isSVNSupported()) {
//this is a core WebDAV live prop
return insertCoreLiveProperty(resource, propAction, livePropSpec, buffer);
}
DAVElement livePropElement = livePropSpec.getPropertyName();
if (!resource.exists() && livePropElement != DAVElement.VERSION_CONTROLLED_CONFIGURATION &&
livePropElement != DAVElement.BASELINE_RELATIVE_PATH) {
return DAVInsertPropAction.NOT_SUPP;
}
String value = null;
DAVResourceURI uri = resource.getResourceURI();
if (livePropElement == DAVElement.GET_LAST_MODIFIED || livePropElement == DAVElement.CREATION_DATE) {
if (resource.getType() == DAVResourceType.PRIVATE && resource.getKind() == DAVResourceKind.VCC) {
return DAVInsertPropAction.NOT_SUPP;
}
if (livePropElement == DAVElement.CREATION_DATE) {
try {
value = SVNDate.formatDate(getLastModifiedTime2(resource));
} catch (SVNException svne) {
return DAVInsertPropAction.NOT_DEF;
}
} else if (livePropElement == DAVElement.GET_LAST_MODIFIED) {
try {
value = SVNDate.formatRFC1123Date(getLastModifiedTime2(resource));
} catch (SVNException svne) {
return DAVInsertPropAction.NOT_DEF;
}
}
value = SVNEncodingUtil.xmlEncodeCDATA(value, true);
} else if (livePropElement == DAVElement.CREATOR_DISPLAY_NAME) {
if (resource.getType() == DAVResourceType.PRIVATE && resource.getKind() == DAVResourceKind.VCC) {
return DAVInsertPropAction.NOT_SUPP;
}
long committedRev = -1;
if (resource.isBaseLined() && resource.getType() == DAVResourceType.VERSION) {
committedRev = resource.getRevision();
} else if (resource.getType() == DAVResourceType.REGULAR || resource.getType() == DAVResourceType.WORKING ||
resource.getType() == DAVResourceType.VERSION) {
try {
committedRev = resource.getCreatedRevisionUsingFS(null);
} catch (SVNException svne) {
value = "###error###";
}
} else {
return DAVInsertPropAction.NOT_SUPP;
}
String lastAuthor = null;
try {
lastAuthor = resource.getAuthor(committedRev);
} catch (SVNException svne) {
value = "###error###";
}
if (lastAuthor == null) {
return DAVInsertPropAction.NOT_DEF;
}
value = SVNEncodingUtil.xmlEncodeCDATA(lastAuthor, true);
} else if (livePropElement == DAVElement.GET_CONTENT_LANGUAGE) {
return DAVInsertPropAction.NOT_SUPP;
} else if (livePropElement == DAVElement.GET_CONTENT_LENGTH) {
if (resource.isCollection() || resource.isBaseLined()) {
return DAVInsertPropAction.NOT_SUPP;
}
long fileSize = 0;
try {
fileSize = resource.getContentLength(null);
value = String.valueOf(fileSize);
} catch (SVNException e) {
value = "0";
}
} else if (livePropElement == DAVElement.GET_CONTENT_TYPE) {
if (resource.isBaseLined() && resource.getType() == DAVResourceType.VERSION) {
return DAVInsertPropAction.NOT_SUPP;
}
if (resource.getType() == DAVResourceType.PRIVATE && resource.getKind() == DAVResourceKind.VCC) {
return DAVInsertPropAction.NOT_SUPP;
}
if (resource.isCollection()) {
value = DAVResource.DEFAULT_COLLECTION_CONTENT_TYPE;
} else {
SVNPropertyValue contentType = null;
try {
contentType = resource.getProperty(null, SVNProperty.MIME_TYPE);
} catch (SVNException svne) {
//
}
if (contentType != null) {
value = contentType.getString();
} else if (!resource.isSVNClient() && getRequest().getContentType() != null) {
value = getRequest().getContentType();
} else {
value = DAVResource.DEFAULT_FILE_CONTENT_TYPE;
}
try {
SVNPropertiesManager.validateMimeType(value);
} catch (SVNException svne) {
return DAVInsertPropAction.NOT_DEF;
}
}
} else if (livePropElement == DAVElement.GET_ETAG) {
if (resource.getType() == DAVResourceType.PRIVATE && resource.getKind() == DAVResourceKind.VCC) {
return DAVInsertPropAction.NOT_SUPP;
}
value = resource.getETag();
} else if (livePropElement == DAVElement.AUTO_VERSION) {
if (getConfig().isAutoVersioning()) {
value = DEFAULT_AUTOVERSION_LINE;
} else {
return DAVInsertPropAction.NOT_DEF;
}
} else if (livePropElement == DAVElement.BASELINE_COLLECTION) {
if (resource.getType() != DAVResourceType.VERSION || !resource.isBaseLined()) {
return DAVInsertPropAction.NOT_SUPP;
}
value = DAVPathUtil.buildURI(uri.getContext(), DAVResourceKind.BASELINE_COLL, resource.getRevision(), null,
true);
} else if (livePropElement == DAVElement.CHECKED_IN) {
String s = null;
if (resource.getType() == DAVResourceType.PRIVATE && resource.getKind() == DAVResourceKind.VCC) {
long revNum = -1;
try {
revNum = resource.getLatestRevision();
s = DAVPathUtil.buildURI(uri.getContext(), DAVResourceKind.BASELINE, revNum, null, false);
StringBuffer buf = SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), s,
null, true, true, null);
value = buf.toString();
} catch (SVNException svne) {
value = "###error###";
}
} else if (resource.getType() != DAVResourceType.REGULAR) {
return DAVInsertPropAction.NOT_SUPP;
} else {
long revToUse = DAVServletUtil.getSafeCreatedRevision((FSRevisionRoot) resource.getRoot(), uri.getPath());
s = DAVPathUtil.buildURI(uri.getContext(), DAVResourceKind.VERSION, revToUse, uri.getPath(), false);
StringBuffer buf = SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.HREF.getName(), s,
null, true, true, null);
value = buf.toString();
}
} else if (livePropElement == DAVElement.VERSION_CONTROLLED_CONFIGURATION) {
if (resource.getType() != DAVResourceType.REGULAR) {
return DAVInsertPropAction.NOT_SUPP;
}
value = DAVPathUtil.buildURI(uri.getContext(), DAVResourceKind.VCC, -1, null, true);
} else if (livePropElement == DAVElement.VERSION_NAME) {
if (resource.getType() != DAVResourceType.VERSION && !resource.isVersioned()) {
return DAVInsertPropAction.NOT_SUPP;
}
if (resource.getType() == DAVResourceType.PRIVATE && resource.getKind() == DAVResourceKind.VCC) {
return DAVInsertPropAction.NOT_SUPP;
}
if (resource.isBaseLined()) {
value = String.valueOf(resource.getRevision());
} else {
try {
long committedRev = resource.getCreatedRevisionUsingFS(null);
value = String.valueOf(committedRev);
value = SVNEncodingUtil.xmlEncodeCDATA(value, true);
} catch (SVNException svne) {
value = "###error###";
}
}
} else if (livePropElement == DAVElement.BASELINE_RELATIVE_PATH) {
if (resource.getType() != DAVResourceType.REGULAR) {
return DAVInsertPropAction.NOT_SUPP;
}
value = SVNEncodingUtil.xmlEncodeCDATA(DAVPathUtil.dropLeadingSlash(uri.getPath()), true);
} else if (livePropElement == DAVElement.MD5_CHECKSUM) {
if (!resource.isCollection() && !resource.isBaseLined() && (resource.getType() == DAVResourceType.REGULAR ||
resource.getType() == DAVResourceType.VERSION || resource.getType() == DAVResourceType.WORKING)) {
try {
value = resource.getMD5Checksum(null);
if (value == null) {
return DAVInsertPropAction.NOT_SUPP;
}
} catch (SVNException svne) {
value = "###error###";
}
} else {
return DAVInsertPropAction.NOT_SUPP;
}
} else if (livePropElement == DAVElement.REPOSITORY_UUID) {
try {
value = resource.getRepositoryUUID(false);
} catch (SVNException svne) {
value = "###error###";
}
} else if (livePropElement == DAVElement.DEADPROP_COUNT) {
if (resource.getType() != DAVResourceType.REGULAR) {
return DAVInsertPropAction.NOT_SUPP;
}
SVNProperties props = null;
try {
props = resource.getSVNProperties(null);
int deadPropertiesCount = props.size();
value = String.valueOf(deadPropertiesCount);
} catch (SVNException svne) {
value = "###error###";
}
} else if (livePropElement == DAVElement.RESOURCE_TYPE) {
if (resource.getType() == DAVResourceType.VERSION) {
if (resource.isBaseLined()) {
StringBuffer buf = SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.BASELINE.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING | SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, null);
value = buf.toString();
}
} else if (resource.getType() == DAVResourceType.REGULAR || resource.getType() == DAVResourceType.WORKING) {
if (resource.isCollection()) {
StringBuffer buf = SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.COLLECTION.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING | SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, null);
value = buf.toString();
} else {
value = "";
}
} else if (resource.getType() == DAVResourceType.HISTORY) {
StringBuffer buf = SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_HISTORY.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING | SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, null);
value = buf.toString();
} else if (resource.getType() == DAVResourceType.WORKSPACE) {
StringBuffer buf = SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.COLLECTION.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING | SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, null);
value = buf.toString();
} else if (resource.getType() == DAVResourceType.ACTIVITY) {
StringBuffer buf = SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.ACTIVITY.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING | SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null, null);
value = buf.toString();
} else {
return DAVInsertPropAction.NOT_DEF;
}
} else if (livePropElement == DAVElement.COMMENT || livePropElement == DAVElement.CREATOR_DISPLAY_NAME ||
livePropElement == DAVElement.DISPLAY_NAME || livePropElement == DAVElement.SOURCE) {
return DAVInsertPropAction.NOT_DEF;
} else {
return DAVInsertPropAction.NOT_SUPP;
}
int ind = NAMESPACES.indexOf(livePropElement.getNamespace());
String prefix = "lp" + ind;
if (propAction == DAVInsertPropAction.INSERT_NAME ||
(propAction == DAVInsertPropAction.INSERT_VALUE && (value == null || value.length() == 0))) {
SVNXMLUtil.openXMLTag(prefix, livePropElement.getName(), SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, buffer);
} else if (propAction == DAVInsertPropAction.INSERT_VALUE) {
SVNXMLUtil.openCDataTag(prefix, livePropElement.getName(), value, null, false, false, buffer);
} else {
Map attrs = new HashMap();
attrs.put("D:name", livePropElement.getName());
attrs.put("D:namespace", livePropElement.getNamespace());
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.SUPPORTED_LIVE_PROPERTY.getName(),
SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, buffer);
}
return propAction;
}
private Date getLastModifiedTime2(DAVResource resource) throws SVNException {
long revision = -1;
if (resource.isBaseLined() && resource.getType() == DAVResourceType.VERSION) {
revision = resource.getRevision();
} else if (resource.getType() == DAVResourceType.REGULAR || resource.getType() == DAVResourceType.WORKING ||
resource.getType() == DAVResourceType.VERSION) {
revision = resource.getCreatedRevisionUsingFS(null);
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_PROPS_NOT_FOUND,
"Failed to determine property"), SVNLogType.NETWORK);
}
return resource.getRevisionDate(revision);
}
private void streamResponse(DAVResource resource, int status, DAVPropsResult propStats) {
DAVResponse response = new DAVResponse(null, resource.getResourceURI().getRequestURI(), null, propStats, status);
DAVXMLUtil.sendOneResponse(response, myResponseBuffer);
}
private void cacheBadProps() {
if (myPropStat404 != null) {
return;
}
myPropStat404 = new StringBuffer();
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null,
myPropStat404);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), SVNXMLUtil.XML_STYLE_PROTECT_CDATA, null,
myPropStat404);
DAVElementProperty elem = myDocRoot.getChild(DAVElement.PROP);
List childrenElements = elem.getChildren();
for (Iterator childrenIter = childrenElements.iterator(); childrenIter.hasNext();) {
DAVElementProperty childElement = (DAVElementProperty) childrenIter.next();
DAVXMLUtil.addEmptyElement(DAVPropfindHandler.this.getNamespaces(), childElement.getName(), myPropStat404);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROP.getName(), myPropStat404);
SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), SVNXMLUtil.XML_STYLE_NORMAL, null, myPropStat404);
myPropStat404.append("HTTP/1.1 404 Not Found");
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.STATUS.getName(), myPropStat404);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.PROPSTAT.getName(), myPropStat404);
}
private DAVPropfindRequest getPropfindRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVPropfindRequest();
}
return myDAVRequest;
}
private static class DAVInsertPropAction {
public static final DAVInsertPropAction NOT_DEF = new DAVInsertPropAction();
public static final DAVInsertPropAction NOT_SUPP = new DAVInsertPropAction();
public static final DAVInsertPropAction INSERT_VALUE = new DAVInsertPropAction();
public static final DAVInsertPropAction INSERT_NAME = new DAVInsertPropAction();
public static final DAVInsertPropAction INSERT_SUPPORTED = new DAVInsertPropAction();
private DAVInsertPropAction() {
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVPropfindRequest extends DAVRequest {
private static final DAVElement PROPFIND = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "propfind");
private static final DAVElement PROPNAME = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "propname");
private static final DAVElement ALLPROP = DAVElement.getElement(DAVElement.DAV_NAMESPACE, "allprop");
public DAVPropfindRequest() {
super();
}
protected void init() throws SVNException {
if (getRoot().getName() != PROPFIND) {
invalidXML();
}
}
public boolean isAllPropRequest() throws SVNException {
return getRoot().hasChild(ALLPROP);
}
public boolean isPropNameRequest() throws SVNException {
return getRoot().hasChild(PROPNAME);
}
public boolean isPropRequest() throws SVNException {
return getRoot().hasChild(DAVElement.PROP);
}
public Collection getPropertyElements() throws SVNException {
DAVElementProperty propElement = getRoot().getChild(DAVElement.PROP);
List props = new LinkedList();
List children = propElement.getChildren();
if (children != null) {
for (Iterator childrenIter = children.iterator(); childrenIter.hasNext();) {
DAVElementProperty child = (DAVElementProperty) childrenIter.next();
props.add(child.getName());
}
}
return props;
}
private DAVElementProperty getRoot() throws SVNException {
if (getRootElement() == null) {
invalidXML();
}
return getRootElement();
}
}

View File

@@ -0,0 +1,51 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Collection;
import java.util.LinkedList;
/**
* @version 1.1.2
* @author TMate Software Ltd.
*/
public class DAVPropsResult {
private StringBuffer myPropStats;
private Collection myNamespaces;
public void addNamespace(String namespace) {
if (myNamespaces == null) {
myNamespaces = new LinkedList();
}
myNamespaces.add(namespace);
}
public void addPropStatsText(String text) {
if (myPropStats == null) {
myPropStats = new StringBuffer();
}
myPropStats.append(text);
}
public Collection getNamespaces() {
return myNamespaces;
}
public String getPropStatsText() {
if (myPropStats != null) {
return myPropStats.toString();
}
return null;
}
}

View File

@@ -0,0 +1,175 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.delta.SVNDeltaReader;
import org.tmatesoft.svn.core.internal.io.fs.FSCommitter;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTransactionInfo;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceState;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.io.ISVNDeltaConsumer;
import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVPutHandler extends ServletDAVHandler {
public DAVPutHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
public void execute() throws SVNException {
DAVResource resource = getRequestedDAVResource(false, false);
if (resource.getType() != DAVResourceType.REGULAR && resource.getType() != DAVResourceType.WORKING) {
String body = "Cannot create resource " + SVNEncodingUtil.xmlEncodeCDATA(getURI()) + " with PUT.";
response(body, DAVServlet.getStatusLine(HttpServletResponse.SC_CONFLICT), HttpServletResponse.SC_CONFLICT);
return;
}
if (resource.isCollection()) {
response("Cannot PUT to a collection.", DAVServlet.getStatusLine(HttpServletResponse.SC_CONFLICT), HttpServletResponse.SC_CONFLICT);
return;
}
DAVResourceState resourceState = getResourceState(resource);
validateRequest(resource, DAVDepth.DEPTH_ZERO, resourceState == DAVResourceState.NULL ? DAV_VALIDATE_PARENT : DAV_VALIDATE_RESOURCE,
null, null, null);
DAVAutoVersionInfo avInfo = autoCheckOut(resource, false);
int mode = DAV_MODE_WRITE_TRUNC;
long[] range = parseRange();
if (range != null) {
mode = DAV_MODE_WRITE_SEEKABLE;
}
SVNDeltaReader deltaReader = null;
DAVException error = null;
try {
deltaReader = openStream(resource, mode);
} catch (DAVException dave) {
error = new DAVException("Unable to PUT new contents for {0}.", new Object[] { SVNEncodingUtil.xmlEncodeCDATA(getURI()) },
HttpServletResponse.SC_FORBIDDEN, dave, 0);
}
if (error == null && range != null) {
error = new DAVException("Resource body read/write cannot use ranges (at this time)", HttpServletResponse.SC_NOT_IMPLEMENTED, 0);
}
DAVException error2 = null;
if (error == null) {
String path = resource.getResourceURI().getPath();
FSRoot root = resource.getRoot();
FSFS fsfs = resource.getFSFS();
FSTransactionInfo txn = resource.getTxnInfo();
Collection lockTokens = resource.getLockTokens();
String userName = resource.getUserName();
FSCommitter committer = getCommitter(fsfs, root, txn, lockTokens, userName);
ISVNDeltaConsumer deltaConsumer = getDeltaConsumer(root, committer, fsfs, userName, lockTokens);
SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
InputStream inputStream = null;
try {
inputStream = getRequestInputStream();
byte[] buffer = new byte[2048];
int readCount = -1;
while ((readCount = inputStream.read(buffer)) != -1) {
if (readCount == 0) {
continue;
}
if (deltaReader != null) {
deltaReader.nextWindow(buffer, 0, readCount, path, deltaConsumer);
} else {
deltaGenerator.sendDelta(path, buffer, readCount, deltaConsumer);
}
}
} catch (IOException ioe) {
error = new DAVException("An error occurred while reading the request body.", HttpServletResponse.SC_BAD_REQUEST, 0);
} catch (SVNException svne) {
error = DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not write the file contents", null);
} finally {
SVNFileUtil.closeFile(inputStream);
if (deltaReader != null) {
try {
deltaReader.reset(path, deltaConsumer);
} catch (SVNException svne) {
error2 = DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"error finalizing applying windows", null);
}
if (error2 != null && error == null) {
error = error2;
}
deltaConsumer.textDeltaEnd(path);
}
}
}
if (error == null) {
resource.setExists(true);
}
try {
autoCheckIn(resource, error != null, false, avInfo);
} catch (DAVException dave) {
error2 = dave;
}
if (error != null) {
throw error;
}
if (error2 != null) {
error2 = new DAVException("The PUT was successful, but there was a problem automatically checking in the resource or its parent collection.",
null, error2.getResponseCode(), error2, 0);
//TODO: add here better logging
}
DAVLockInfoProvider lockProvider = null;
try {
lockProvider = DAVLockInfoProvider.createLockInfoProvider(this, false);
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"The file was PUT successfully, but there was a problem opening the lock database which prevents inheriting locks from the parent resources.",
null);
}
notifyCreated(resource, lockProvider, resourceState, DAVDepth.DEPTH_ZERO);
handleDAVCreated(null, "Resource", resourceState == DAVResourceState.EXISTS);
}
protected DAVRequest getDAVRequest() {
return null;
}
}

View File

@@ -0,0 +1,207 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.OutputStream;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVReplayHandler extends DAVReportHandler implements ISVNEditor {
private DAVReplayRequest myDAVRequest;
private DAVReportHandler myCommonReportHandler;
public DAVReplayHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
myCommonReportHandler = commonReportHandler;
}
protected DAVRequest getDAVRequest() {
return getReplayRequest();
}
private DAVReplayRequest getReplayRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVReplayRequest();
}
return myDAVRequest;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace("The request does not contain the 'svn:' namespace, so it is not going" +
" to have an svn:revision element. That element is required.");
setDAVResource(getRequestedDAVResource(false, false));
writeXMLHeader(null);
getRequestedRepository().replay(getReplayRequest().getLowRevision(),
getReplayRequest().getRevision(),
getReplayRequest().isSendDeltas(),
this);
writeXMLFooter(null);
}
private SVNRepository getRequestedRepository() throws SVNException {
if (getDAVResource().getResourceURI().getPath() == null || getDAVResource().getResourceURI().getPath().length() == 0) {
return getDAVResource().getRepository();
}
SVNURL resourceURL = getDAVResource().getRepository().getLocation();
SVNURL resultURL = resourceURL.appendPath(getDAVResource().getResourceURI().getPath(), true);
return SVNRepositoryFactory.create(resultURL);
}
public void targetRevision(long revision) throws SVNException {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "target-revision", SVNXMLUtil.XML_STYLE_SELF_CLOSING, "rev", String.valueOf(revision), null);
write(xmlBuffer);
}
public void openRoot(long revision) throws SVNException {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "open-root", SVNXMLUtil.XML_STYLE_SELF_CLOSING, REVISION_ATTR, String.valueOf(revision), null);
write(xmlBuffer);
}
public void deleteEntry(String path, long revision) throws SVNException {
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, path);
attrs.put(REVISION_ATTR, String.valueOf(revision));
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "delete-entry", SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, null);
write(xmlBuffer);
}
public void absentDir(String path) throws SVNException {
}
public void absentFile(String path) throws SVNException {
}
public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
addEntry("add-directory", path, copyFromPath, copyFromRevision);
}
public void openDir(String path, long revision) throws SVNException {
openEntry("open-directory", path, revision);
}
public void changeDirProperty(String name, SVNPropertyValue value) throws SVNException {
changeEntryProperty("change-directory-prop", name, value);
}
public void closeDir() throws SVNException {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "close-directory", SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, null);
write(xmlBuffer);
}
public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException {
addEntry("add-file", path, copyFromPath, copyFromRevision);
}
public void openFile(String path, long revision) throws SVNException {
openEntry("open-file", path, revision);
}
public void changeFileProperty(String path, String name, SVNPropertyValue value) throws SVNException {
changeEntryProperty("change-file-prop", name, value);
}
public void closeFile(String path, String textChecksum) throws SVNException {
Map attrs = new SVNHashMap();
if (textChecksum != null) {
attrs.put(CHECKSUM_ATTR, textChecksum);
}
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "close-file", SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, null);
write(xmlBuffer);
}
public SVNCommitInfo closeEdit() throws SVNException {
return null;
}
public void applyTextDelta(String path, String baseChecksum) throws SVNException {
Map attrs = new SVNHashMap();
if (baseChecksum != null) {
attrs.put(CHECKSUM_ATTR, baseChecksum);
}
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "apply-textdelta", SVNXMLUtil.XML_STYLE_PROTECT_CDATA, attrs, null);
write(xmlBuffer);
}
public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
writeTextDeltaChunk(diffWindow);
return null;
}
public void textDeltaEnd(String path) throws SVNException {
textDeltaChunkEnd();
setWriteTextDeltaHeader(true);
StringBuffer xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "apply-textdelta", null);
write(xmlBuffer);
}
public void abortEdit() throws SVNException {
}
private void addEntry(String tagName, String path, String copyfromPath, long copyfromRevision) throws SVNException {
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, path);
if (copyfromPath != null) {
attrs.put(COPYFROM_PATH_ATTR, copyfromPath);
attrs.put(COPYFROM_REVISION_ATTR, String.valueOf(copyfromRevision));
}
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, null);
write(xmlBuffer);
}
private void openEntry(String tagName, String path, long revision) throws SVNException {
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, path);
attrs.put(REVISION_ATTR, String.valueOf(revision));
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_SELF_CLOSING, attrs, null);
write(xmlBuffer);
}
private void changeEntryProperty(String tagName, String name, SVNPropertyValue propertyValue) throws SVNException {
StringBuffer xmlBuffer = new StringBuffer();
if (propertyValue != null) {
String value = SVNBase64.byteArrayToBase64(SVNPropertyValue.getPropertyAsBytes(propertyValue));
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_PROTECT_CDATA, NAME_ATTR, name, xmlBuffer);
xmlBuffer.append(value);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, xmlBuffer);
} else {
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, name);
attrs.put(DELETE_ATTR, Boolean.TRUE.toString());
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, "", attrs, xmlBuffer);
}
write(xmlBuffer);
}
}

View File

@@ -0,0 +1,99 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVReplayRequest extends DAVRequest {
private static final DAVElement EDITOR_REPORT = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "editor-report");
private static final DAVElement LOW_WATER_MARK = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "low-water-mark");
private static final DAVElement SEND_DELTAS = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "send-deltas");
boolean myIsSendDeltas = true;
long myLowRevision = DAVResource.INVALID_REVISION;
long myRevision = DAVResource.INVALID_REVISION;
public boolean isSendDeltas() {
return myIsSendDeltas;
}
private void setSendDeltas(boolean isSendDelta) {
myIsSendDeltas = isSendDelta;
}
public long getLowRevision() {
return myLowRevision;
}
private void setLowRevision(long lowRevision) {
myLowRevision = lowRevision;
}
public long getRevision() {
return myRevision;
}
private void setRevision(long revision) {
myRevision = revision;
}
protected void init() throws SVNException {
DAVElementProperty rootElement = getRootElement();
rootElement.setElementName(EDITOR_REPORT);
List children = rootElement.getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext();) {
DAVElementProperty property = (DAVElementProperty) iterator.next();
DAVElement element = property.getName();
if (element == DAVElement.REVISION) {
assertNullCData(element, property);
try {
setRevision(Long.parseLong(property.getFirstValue(true)));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == LOW_WATER_MARK) {
assertNullCData(element, property);
try {
setLowRevision(Long.parseLong(property.getFirstValue(true)));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == SEND_DELTAS) {
assertNullCData(element, property);
int sendDeltas = Integer.parseInt(property.getFirstValue(true));
setSendDeltas(sendDeltas != 0);
}
}
if (!SVNRevision.isValidRevisionNumber(getRevision())) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Request was missing the revision argument."), SVNLogType.NETWORK);
}
if (!SVNRevision.isValidRevisionNumber(getLowRevision())) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Request was missing the low-water-mark argument."), SVNLogType.NETWORK);
}
}
}

View File

@@ -0,0 +1,337 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNHashSet;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVReportHandler extends ServletDAVHandler {
protected static final Set REPORT_NAMESPACES = new SVNHashSet();
protected static final String PATH_ATTR = "path";
protected static final String REVISION_ATTR = "rev";
protected static final String COPYFROM_PATH_ATTR = "copyfrom-path";
protected static final String COPYFROM_REVISION_ATTR = "copyfrom-rev";
protected static final String TXDELTA_ATTR = "txdelta";
protected static final String CHECKSUM_ATTR = "checksum";
protected static final String DELETE_ATTR = "del";
protected static final String LOCK_TOKEN_ATTR = "lock-token";
protected static final String LINKPATH_ATTR = "linkpath";
protected static final String DEPTH_ATTR = "depth";
protected static final String START_EMPTY_ATTR = "start-empty";
protected static final String SEND_ALL_ATTR = "send-all";
protected static final String BASE_CHECKSUM_ATTR = "base-checksum";
protected static final String BC_URL_ATTR = "bc-url";
private DAVRepositoryManager myRepositoryManager;
private HttpServletRequest myRequest;
private HttpServletResponse myResponse;
private DAVReportHandler myReportHandler;
private DAVResource myDAVResource;
private OutputStream myDiffWindowWriter;
private boolean myWriteTextDeltaHeader = true;
private boolean mySVNDiffVersion = false;
private boolean myIsUnknownReport;
static {
REPORT_NAMESPACES.add(DAVElement.SVN_NAMESPACE);
}
protected DAVReportHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
myRepositoryManager = connector;
myRequest = request;
myResponse = response;
}
protected List getNamespaces() {
return super.getNamespaces();
}
protected DAVRequest getDAVRequest() {
return getReportHandler().getDAVRequest();
}
private DAVReportHandler getReportHandler() {
return myReportHandler;
}
private void setReportHandler(DAVReportHandler reportHandler) {
myReportHandler = reportHandler;
}
protected DAVResource getDAVResource() {
return myDAVResource;
}
protected void setDAVResource(DAVResource DAVResource) {
myDAVResource = DAVResource;
}
protected void checkSVNNamespace(String errorMessage) throws DAVException {
errorMessage = errorMessage == null ? "The request does not contain the 'svn:' namespace, so it is not going to have certain required elements." : errorMessage;
List namespaces = getNamespaces();
if (!namespaces.contains(DAVElement.SVN_NAMESPACE)) {
throw new DAVException(errorMessage, HttpServletResponse.SC_BAD_REQUEST, SVNLogType.NETWORK, DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE);
}
}
public boolean doCompress() {
return mySVNDiffVersion;
}
public void setSVNDiffVersion(boolean SVNDiffVersion) {
mySVNDiffVersion = SVNDiffVersion;
}
private boolean isWriteTextDeltaHeader() {
return myWriteTextDeltaHeader;
}
protected void setWriteTextDeltaHeader(boolean writeTextDeltaHeader) {
myWriteTextDeltaHeader = writeTextDeltaHeader;
}
protected void startElement(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
if (parent == null) {
initReportHandler(element);
}
getReportHandler().handleAttributes(parent, element, attrs);
}
protected void handleAttributes(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
getDAVRequest().startElement(parent, element, attrs);
}
protected void endElement(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
getReportHandler().handleCData(parent, element, cdata);
}
protected void handleCData(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
getDAVRequest().endElement(parent, element, cdata);
}
public void execute() throws SVNException {
long read = readInput(false);
if (myIsUnknownReport) {
throw new DAVException("The requested report is unknown.", null, HttpServletResponse.SC_NOT_IMPLEMENTED, null, SVNLogType.DEFAULT, Level.FINE,
null, DAVXMLUtil.SVN_DAV_ERROR_TAG, DAVElement.SVN_DAV_ERROR_NAMESPACE, SVNErrorCode.UNSUPPORTED_FEATURE.getCode(), null);
}
if (read == 0) {
throw new DAVException("The request body must specify a report.", HttpServletResponse.SC_BAD_REQUEST, SVNLogType.NETWORK);
}
setDefaultResponseHeaders();
setResponseContentType(DEFAULT_XML_CONTENT_TYPE);
setResponseStatus(HttpServletResponse.SC_OK);
getReportHandler().execute();
}
private void initReportHandler(DAVElement rootElement) {
myIsUnknownReport = false;
if (rootElement == DATED_REVISIONS_REPORT) {
setReportHandler(new DAVDatedRevisionHandler(myRepositoryManager, myRequest, myResponse));
} else if (rootElement == FILE_REVISIONS_REPORT) {
setReportHandler(new DAVFileRevisionsHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == GET_LOCATIONS) {
setReportHandler(new DAVGetLocationsHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == LOG_REPORT) {
setReportHandler(new DAVLogHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == MERGEINFO_REPORT) {
setReportHandler(new DAVMergeInfoHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == GET_LOCKS_REPORT) {
setReportHandler(new DAVGetLocksHandler(myRepositoryManager, myRequest, myResponse));
} else if (rootElement == REPLAY_REPORT) {
setReportHandler(new DAVReplayHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == UPDATE_REPORT) {
setReportHandler(new DAVUpdateHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == GET_LOCATION_SEGMENTS) {
setReportHandler(new DAVGetLocationSegmentsHandler(myRepositoryManager, myRequest, myResponse, this));
} else if (rootElement == GET_DELETED_REVISION_REPORT) {
setReportHandler(new DAVGetDeletedRevisionHandler(myRepositoryManager, myRequest, myResponse, this));
} else {
myIsUnknownReport = true;
setReportHandler(new DumpReportHandler(myRepositoryManager, myRequest, myResponse));
}
}
protected void write(String string) throws SVNException {
try {
getResponseWriter().write(string);
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, e), e, SVNLogType.NETWORK);
}
}
protected void write(StringBuffer stringBuffer) throws SVNException {
write(stringBuffer.toString());
}
protected void writeXMLHeader(String tagName) throws SVNException {
StringBuffer xmlBuffer = new StringBuffer();
addXMLHeader(xmlBuffer, tagName);
write(xmlBuffer);
}
protected void writeXMLFooter(String tagName) throws SVNException {
StringBuffer xmlBuffer = new StringBuffer();
addXMLFooter(xmlBuffer, tagName);
write(xmlBuffer);
}
protected void addXMLHeader(StringBuffer xmlBuffer, String tagName) {
SVNXMLUtil.addXMLHeader(xmlBuffer);
DAVElementProperty rootElement = getDAVRequest().getRootElement();
tagName = tagName == null ? rootElement.getName().getName() : tagName;
DAVXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, REPORT_NAMESPACES,
xmlBuffer, false);
}
protected void addXMLFooter(StringBuffer xmlBuffer, String tagName) {
DAVElementProperty rootElement = getDAVRequest().getRootElement();
tagName = tagName == null ? rootElement.getName().getName() : tagName;
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, xmlBuffer);
}
protected void writeTextDeltaChunk(SVNDiffWindow diffWindow) throws SVNException {
if (myDiffWindowWriter == null) {
myDiffWindowWriter = new DAVBase64OutputStream(getResponseWriter());
}
try {
diffWindow.writeTo(myDiffWindowWriter, isWriteTextDeltaHeader(), doCompress());
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, e), e, SVNLogType.NETWORK);
} finally {
setWriteTextDeltaHeader(false);
}
}
protected void textDeltaChunkEnd() throws SVNException {
if (myDiffWindowWriter != null) {
try {
myDiffWindowWriter.flush();
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, e), e, SVNLogType.NETWORK);
}
}
myDiffWindowWriter = null;
}
protected void writePropertyTag(String tagName, String propertyName, SVNPropertyValue propertyValue) throws SVNException {
StringBuffer xmlBuffer;
if (propertyValue == null){
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_SELF_CLOSING, NAME_ATTR, propertyName, null);
write(xmlBuffer);
return;
}
String value = propertyValue.getString();
boolean isXMLSafe = true;
if (propertyValue.isBinary()){
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPORT);
decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
try {
value = decoder.decode(ByteBuffer.wrap(propertyValue.getBytes())).toString();
} catch (CharacterCodingException e) {
isXMLSafe = false;
}
}
if (value != null){
isXMLSafe = SVNEncodingUtil.isXMLSafe(value);
}
if (!isXMLSafe){
byte[] buffer = null;
if (value != null){
try {
buffer = value.getBytes(UTF8_ENCODING);
} catch (UnsupportedEncodingException e) {
buffer = value.getBytes();
}
} else {
buffer = propertyValue.getBytes();
}
value = SVNBase64.byteArrayToBase64(buffer);
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, propertyName);
attrs.put(ServletDAVHandler.ENCODING_ATTR, BASE64_ENCODING);
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_PROTECT_CDATA, attrs, null);
write(xmlBuffer);
write(value);
xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, null);
write(xmlBuffer);
} else {
xmlBuffer = SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, propertyValue.getString(), NAME_ATTR, propertyName, null);
write(xmlBuffer);
}
}
private static class DumpReportHandler extends DAVReportHandler {
private DAVRequest myDAVRequest;
protected DumpReportHandler(DAVRepositoryManager connector, HttpServletRequest request, HttpServletResponse response) {
super(connector, request, response);
}
protected DAVRequest getDAVRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVRequest() {
protected void init() throws SVNException {
}
};
}
return myDAVRequest;
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public abstract class DAVRequest {
protected static final String NAME_ATTR = "name";
protected static final String NAMESPACE_ATTR = "namespace";
private DAVElementProperty myRootElementProperty;
private DAVElementProperty myCurrentElement;
public DAVElementProperty getRootElement() {
return myRootElementProperty;
}
protected String getRootElementAttributeValue(String name) {
if (myRootElementProperty != null) {
return myRootElementProperty.getAttributeValue(name);
}
return null;
}
public void startElement(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
if (parent == null) {
myCurrentElement = new DAVElementProperty(element, null);
myCurrentElement.setAttributes(attrs);
myRootElementProperty = myCurrentElement;
} else {
myCurrentElement = myCurrentElement.addChild(element, attrs);
}
}
public void endElement(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
if (myCurrentElement == null || element != myCurrentElement.getName()) {
invalidXML();
}
if (cdata != null) {
myCurrentElement.addValue(cdata.toString());
}
myCurrentElement = myCurrentElement.getParent();
if (myCurrentElement == null && parent != null) {
invalidXML();
}
}
protected abstract void init() throws SVNException;
protected void invalidXML() throws SVNException {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.XML_MALFORMED, "Malformed XML"), SVNLogType.NETWORK);
}
protected void invalidXML(DAVElement element) throws SVNException {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.XML_MALFORMED, "\"The request's ''{0}'' element is malformed; there is a problem with the client.", element.getName()), SVNLogType.NETWORK);
}
protected void assertNullCData(DAVElement element, DAVElementProperty property) throws SVNException {
if (property.getValues() == null) {
invalidXML(element);
}
}
}

View File

@@ -0,0 +1,128 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.internal.io.fs.FSEntry;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionNode;
import org.tmatesoft.svn.core.internal.io.fs.FSRoot;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceType;
import org.tmatesoft.svn.core.internal.server.dav.handlers.IDAVResourceWalkHandler.CallType;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVResourceWalker {
public static final int DAV_WALKTYPE_AUTH = 0x0001;
public static final int DAV_WALKTYPE_NORMAL = 0x0002;
public static final int DAV_WALKTYPE_LOCKNULL = 0x0004;
private LinkedList myIfHeaders;
private DAVResource myResource;
private DAVLockInfoProvider myLockInfoProvider;
private DAVLockScope myLockScope;
private int myFlags;
private int myWalkType;
private FSRoot myRoot;
public DAVResponse walk(DAVLockInfoProvider lockInfoProvider, DAVResource resource, LinkedList ifHeaders, int flags, DAVLockScope lockScope,
int walkType, IDAVResourceWalkHandler handler, DAVDepth depth) throws DAVException {
myIfHeaders = ifHeaders;
myLockInfoProvider = lockInfoProvider;
myResource = resource.dup();
myFlags = flags;
myWalkType = walkType;
myRoot = resource.getRoot();
myLockScope = lockScope;
return doWalk(handler, null, depth);
}
private DAVResponse doWalk(IDAVResourceWalkHandler handler, DAVResponse response, DAVDepth depth) throws DAVException {
boolean isDir = myResource.isCollection();
response = handler.handleResource(response, myResource, myLockInfoProvider, myIfHeaders, myFlags, myLockScope,
isDir ? CallType.COLLECTION : CallType.MEMBER);
if (depth == DAVDepth.DEPTH_ZERO || !isDir) {
return response;
}
if (myResource.isWorking()) {
return response;
}
if (myResource.getType() != DAVResourceType.REGULAR) {
throw new DAVException("Walking the resource hierarchy can only be done on 'regular' resources [at this time].",
HttpServletResponse.SC_METHOD_NOT_ALLOWED, 0);
}
//TODO: log here that we are listing a dir
myResource.setExists(true);
myResource.setCollection(false);
FSRevisionNode node = null;
Map children = null;
try {
node = myRoot.getRevisionNode(myResource.getResourceURI().getPath());
children = node.getDirEntries(myRoot.getOwner());
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not fetch collection members", null);
}
for (Iterator childrenIter = children.keySet().iterator(); childrenIter.hasNext(); ) {
String childName = (String) childrenIter.next();
FSEntry childEntry = (FSEntry) children.get(childName);
if ((myWalkType & DAV_WALKTYPE_AUTH) != 0) {
//
}
String uriPath = myResource.getResourceURI().getURI();
String reposPath = myResource.getResourceURI().getPath();
myResource.getResourceURI().setURI(SVNPathUtil.append(uriPath, childName));
myResource.getResourceURI().setPath(SVNPathUtil.append(reposPath, childName));
if (childEntry.getType() == SVNNodeKind.FILE) {
response = handler.handleResource(response, myResource, myLockInfoProvider, myIfHeaders, myFlags, myLockScope, CallType.MEMBER);
} else {
myResource.setCollection(true);
try {
response = doWalk(handler, response, DAVDepth.decreaseDepth(depth));
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"could not decrease depth", null);
}
myResource.setCollection(false);
}
myResource.getResourceURI().setURI(uriPath);
myResource.getResourceURI().setPath(reposPath);
}
return response;
}
}

View File

@@ -0,0 +1,54 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
/**
* @version 1.1.2
* @author TMate Software Ltd.
*/
public class DAVResponse {
private DAVResponse myNextResponse;
private DAVPropsResult myPropResult;
private int myStatusCode;
private String myDescription;
private String myHref;
public DAVResponse(String description, String href, DAVResponse nextResponse, DAVPropsResult propResult, int statusCode) {
myDescription = description;
myHref = href;
myNextResponse = nextResponse;
myStatusCode = statusCode;
myPropResult = propResult;
}
public DAVResponse getNextResponse() {
return myNextResponse;
}
public int getStatusCode() {
return myStatusCode;
}
public String getDescription() {
return myDescription;
}
public String getHref() {
return myHref;
}
public DAVPropsResult getPropResult() {
return myPropResult;
}
}

View File

@@ -0,0 +1,67 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.http.HTTPHeader;
import org.tmatesoft.svn.core.internal.server.dav.DAVDepth;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceState;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class DAVUnlockHandler extends ServletDAVHandler {
protected DAVUnlockHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response) {
super(repositoryManager, request, response);
}
public void execute() throws SVNException {
String lockToken = getRequestHeader(HTTPHeader.LOCK_TOKEN_HEADER);
if (lockToken == null) {
sendError(HttpServletResponse.SC_BAD_REQUEST, "Unlock failed: No Lock-Token specified in header");
return;
}
if (lockToken.indexOf('<') == -1) {
sendError(HttpServletResponse.SC_BAD_REQUEST, "Unlock failed: Malformed Lock-Token header");
return;
}
lockToken = lockToken.substring(1);
if (lockToken.charAt(lockToken.length() - 1) != '>') {
sendError(HttpServletResponse.SC_BAD_REQUEST, "Unlock failed: Malformed Lock-Token header");
return;
}
lockToken = lockToken.substring(0, lockToken.length() - 1);
DAVResource resource = getRequestedDAVResource(false, false);
DAVResourceState resourceState = getResourceState(resource);
validateRequest(resource, DAVDepth.DEPTH_ZERO, resourceState == DAVResourceState.LOCK_NULL ?
ServletDAVHandler.DAV_VALIDATE_PARENT : ServletDAVHandler.DAV_VALIDATE_RESOURCE, null, lockToken, null);
unlock(resource, lockToken);
setResponseStatus(HttpServletResponse.SC_NO_CONTENT);
}
protected DAVRequest getDAVRequest() {
return null;
}
}

View File

@@ -0,0 +1,45 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.LinkedList;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVUnlockWalker implements IDAVResourceWalkHandler {
private ServletDAVHandler myServletHandler;
private String myLockToken;
public DAVUnlockWalker(String lockToken, ServletDAVHandler servletHandler) {
myLockToken = lockToken;
myServletHandler = servletHandler;
}
public DAVResponse handleResource(DAVResponse response, DAVResource resource, DAVLockInfoProvider lockInfoProvider, LinkedList ifHeaders,
int flags, DAVLockScope lockScope, CallType callType)
throws DAVException {
if (resource.isWorking()) {
myServletHandler.autoCheckIn(resource, false, true, null);
}
lockInfoProvider.removeLock(resource, myLockToken);
return null;
}
}

View File

@@ -0,0 +1,804 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.io.fs.FSFS;
import org.tmatesoft.svn.core.internal.io.fs.FSRepository;
import org.tmatesoft.svn.core.internal.io.fs.FSRevisionRoot;
import org.tmatesoft.svn.core.internal.io.fs.FSTranslateReporter;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVRepositoryManager;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVResourceKind;
import org.tmatesoft.svn.core.internal.server.dav.DAVServletUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.util.SVNHashSet;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.internal.wc.SVNAdminDeltifier;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVUpdateHandler extends DAVReportHandler implements ISVNEditor {
private static Set UPDATE_REPORT_NAMESPACES = new SVNHashSet();
private static final DAVElement ENTRY = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "entry");
private static final DAVElement MISSING = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "missing");
private DAVUpdateRequest myDAVRequest;
private FSTranslateReporter myReporter;
private boolean myInitialized = false;
private boolean myResourceWalk = false;
private FSRepository mySourceRepository;
private FSRevisionRoot myRevisionRoot;
private long myRevision = DAVResource.INVALID_REVISION;
private SVNURL myDstURL = null;
private String myDstPath = null;
private String myAnchor = null;
private SVNDepth myDepth = SVNDepth.UNKNOWN;
private SVNDepth myRequestedDepth = SVNDepth.UNKNOWN;
private Map myPathMap = null;
private long myEntryRevision = DAVResource.INVALID_REVISION;
private String myEntryLinkPath = null;
private boolean myEntryStartEmpty = false;
private String myEntryLockToken = null;
private String myFileBaseChecksum = null;
private boolean myFileTextChanged = false;
private EditorEntry myFileEditorEntry;
private DAVReportHandler myCommonReportHandler;
Stack myEditorEntries;
static {
UPDATE_REPORT_NAMESPACES.add(DAVElement.SVN_NAMESPACE);
UPDATE_REPORT_NAMESPACES.add(DAVElement.SVN_DAV_PROPERTY_NAMESPACE);
}
public DAVUpdateHandler(DAVRepositoryManager repositoryManager, HttpServletRequest request, HttpServletResponse response,
DAVReportHandler commonReportHandler) {
super(repositoryManager, request, response);
setSVNDiffVersion(getSVNDiffVersion());
myCommonReportHandler = commonReportHandler;
}
public DAVRequest getDAVRequest() {
return getUpdateRequest();
}
private DAVUpdateRequest getUpdateRequest() {
if (myDAVRequest == null) {
myDAVRequest = new DAVUpdateRequest();
}
return myDAVRequest;
}
private FSTranslateReporter getReporter() {
return myReporter;
}
private void setReporter(FSTranslateReporter reporter) {
myReporter = reporter;
}
private long getRevision() {
return myRevision;
}
private void setRevision(long revision) {
myRevision = revision;
}
private SVNURL getDstURL() {
return myDstURL;
}
private void setDstURL(SVNURL dstURL) {
myDstURL = dstURL;
}
private String getDstPath() {
return myDstPath;
}
private void setDstPath(String dstPath) {
myDstPath = dstPath;
}
private String getAnchor() {
return myAnchor;
}
private void setAnchor(String anchor) {
myAnchor = anchor;
}
private SVNDepth getDepth() {
return myDepth;
}
private void setDepth(SVNDepth depth) {
myDepth = depth;
}
private Map getPathMap() {
if (myPathMap == null) {
myPathMap = new SVNHashMap();
}
return myPathMap;
}
private void addToPathMap(String path, String linkPath) {
String normalizedPath = DAVPathUtil.normalize(path);
String repositoryPath = linkPath == null ? normalizedPath : linkPath;
getPathMap().put(SVNPathUtil.getAbsolutePath(path), repositoryPath);
}
private boolean isInitialized() {
return myInitialized;
}
private void setInitialized(boolean initialized) {
myInitialized = initialized;
}
private boolean isResourceWalk() {
return myResourceWalk;
}
private void setResourceWalk(boolean resourceWalk) {
myResourceWalk = resourceWalk;
}
private FSRepository getSourceRepository() {
return mySourceRepository;
}
private void setSourceRepository(FSRepository sourceRepository) {
mySourceRepository = sourceRepository;
}
private long getEntryRevision() {
return myEntryRevision;
}
private void setEntryRevision(long entryRevision) {
myEntryRevision = entryRevision;
}
private String getEntryLinkPath() {
return myEntryLinkPath;
}
private void setEntryLinkPath(String entryLinkPath) {
myEntryLinkPath = entryLinkPath;
}
private boolean isEntryStartEmpty() {
return myEntryStartEmpty;
}
private void setEntryStartEmpty(boolean entryStartEmpty) {
myEntryStartEmpty = entryStartEmpty;
}
private String getEntryLockToken() {
return myEntryLockToken;
}
private void setEntryLockToken(String entryLockToken) {
myEntryLockToken = entryLockToken;
}
private String getFileBaseChecksum() {
return myFileBaseChecksum;
}
private void setFileBaseChecksum(String fileBaseChecksum) {
myFileBaseChecksum = fileBaseChecksum;
}
private boolean isFileTextChanged() {
return myFileTextChanged;
}
private void setFileTextChanged(boolean fileTextChanged) {
myFileTextChanged = fileTextChanged;
}
private void setFileIsAdded(boolean isAdded) {
if (myFileEditorEntry == null) {
myFileEditorEntry = new EditorEntry(isAdded);
} else {
myFileEditorEntry.setAdded(isAdded);
}
}
private EditorEntry getFileEditorEntry() {
return myFileEditorEntry;
}
private Stack getEditorEntries() {
if (myEditorEntries == null) {
myEditorEntries = new Stack();
}
return myEditorEntries;
}
private void initialize() throws SVNException {
if (!isInitialized()) {
getUpdateRequest().init();
setDAVResource(getRequestedDAVResource(false, false));
long targetRevision = getUpdateRequest().getRevision();
if (!SVNRevision.isValidRevisionNumber(targetRevision)) {
try {
targetRevision = getDAVResource().getLatestRevision();
} catch (SVNException svne) {
throw DAVException.convertError(svne.getErrorMessage(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Could not determine the youngest revision for the update process.", null);
}
}
setRevision(targetRevision);
myRequestedDepth = getUpdateRequest().getDepth();
if (!getUpdateRequest().isDepthRequested() && !getUpdateRequest().isRecursiveRequested() && myRequestedDepth == SVNDepth.UNKNOWN) {
myRequestedDepth = SVNDepth.INFINITY;
}
String srcPath = getRepositoryManager().getRepositoryRelativePath(getUpdateRequest().getSrcURL());
setAnchor(srcPath);
SVNURL dstURL = getUpdateRequest().getDstURL();
String dstPath;
if (dstURL != null) {
dstPath = getRepositoryManager().getRepositoryRelativePath(dstURL);
setDstPath(dstPath);
setDstURL(getRepositoryManager().convertHttpToFile(dstURL));
addToPathMap(SVNPathUtil.getAbsolutePath(SVNPathUtil.append(srcPath, getUpdateRequest().getTarget())), dstPath);
}
FSFS fsfs = getDAVResource().getFSFS();
myRevisionRoot = fsfs.createRevisionRoot(targetRevision);
SVNURL repositoryURL = getRepositoryManager().convertHttpToFile(getUpdateRequest().getSrcURL());
FSRepository repository = (FSRepository) SVNRepositoryFactory.create(repositoryURL);
FSTranslateReporter reporter = repository.beginReport(getRevision(),
getDstURL(),
getUpdateRequest().getTarget(),
getUpdateRequest().isIgnoreAncestry(),
getUpdateRequest().isTextDeltas(),
getUpdateRequest().isSendCopyFromArgs(),
myRequestedDepth,
this);
setReporter(reporter);
setSourceRepository(repository);
setInitialized(true);
}
}
protected void handleAttributes(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException {
if (element == ENTRY && parent == ServletDAVHandler.UPDATE_REPORT) {
setEntryLinkPath(attrs.getValue(LINKPATH_ATTR));
setEntryLockToken(attrs.getValue(LOCK_TOKEN_ATTR));
String revisionString = attrs.getValue(REVISION_ATTR);
if (revisionString == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Missing XML attribute: rev"), SVNLogType.NETWORK);
}
try {
setEntryRevision(Long.parseLong(revisionString));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
setDepth(SVNDepth.fromString(attrs.getValue(DEPTH_ATTR)));
if (attrs.getValue(START_EMPTY_ATTR) != null) {
setEntryStartEmpty(true);
}
} else if (element != MISSING || parent != ServletDAVHandler.UPDATE_REPORT) {
if (isInitialized()) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Invalid XML elements order: entry elements should follow any other."), SVNLogType.NETWORK);
}
getDAVRequest().startElement(parent, element, attrs);
}
}
protected void handleCData(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException {
if (element == ENTRY && parent == ServletDAVHandler.UPDATE_REPORT) {
handleEntry(cdata.toString(), false);
} else if (element == MISSING && parent == ServletDAVHandler.UPDATE_REPORT) {
handleEntry(cdata.toString(), true);
} else {
getDAVRequest().endElement(parent, element, cdata);
}
}
private void handleEntry(String entryPath, boolean deletePath) throws SVNException {
initialize();
try {
if (deletePath) {
getReporter().deletePath(entryPath);
} else {
if (getEntryLinkPath() == null) {
getReporter().setPath(entryPath, getEntryLockToken(), getEntryRevision(), getDepth(), isEntryStartEmpty());
} else {
SVNURL linkURL = getDAVResource().getRepository().getLocation().appendPath(getEntryLinkPath(), true);
getReporter().linkPath(linkURL, entryPath, getEntryLockToken(), getEntryRevision(), getDepth(), isEntryStartEmpty());
}
if (getEntryLinkPath() != null && getDstPath() == null) {
String path = SVNPathUtil.append(getAnchor(), SVNPathUtil.append(getUpdateRequest().getTarget(), entryPath));
addToPathMap(path, getEntryLinkPath());
}
refreshEntry();
}
} catch (SVNException e) {
getReporter().abortReport();
getReporter().closeRepository();
throw e;
}
}
private void refreshEntry() {
setEntryLinkPath(null);
setEntryLockToken(null);
setEntryRevision(DAVResource.INVALID_REVISION);
setEntryStartEmpty(false);
}
private String getRealPath(String path) {
path = SVNPathUtil.getAbsolutePath(SVNPathUtil.append(getAnchor(), path));
if (getPathMap().isEmpty()) {
return path;
}
String repositoryPath = (String) getPathMap().get(path);
if (repositoryPath != null) {
return repositoryPath;
}
String tmpPath = path;
do {
tmpPath = SVNPathUtil.removeTail(tmpPath);
repositoryPath = (String) getPathMap().get(tmpPath);
if (repositoryPath != null) {
return SVNPathUtil.append(repositoryPath, path.substring(tmpPath.length()));
}
} while (SVNPathUtil.getSegmentsCount(tmpPath) > 0);
return path;
}
public void execute() throws SVNException {
myCommonReportHandler.checkSVNNamespace("The request does not contain the 'svn:' namespace, so it is not going to have" +
" an svn:target-revision element. That element is required.");
writeXMLHeader(null);
try {
getReporter().finishReport();
} catch (SVNException e) {
getReporter().abortReport();
throw e;
} finally {
getReporter().closeRepository();
}
if (getDstPath() != null && getUpdateRequest().isResourceWalk()) {
if (SVNNodeKind.DIR == getDAVResource().getRepository().checkPath(getDstPath(), getRevision())) {
setResourceWalk(true);
}
}
if (isResourceWalk()) {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "resource-walk", SVNXMLUtil.XML_STYLE_NORMAL, null, null);
write(xmlBuffer);
FSFS fsfs = getSourceRepository().getFSFS();
SVNAdminDeltifier deltifier = new SVNAdminDeltifier(fsfs, myRequestedDepth, true, false, false, this);
FSRevisionRoot zeroRoot = fsfs.createRevisionRoot(0);
FSRevisionRoot requestedRoot = fsfs.createRevisionRoot(getRevision());
deltifier.deltifyDir(zeroRoot, "", getUpdateRequest().getTarget(), requestedRoot, getDstPath());
xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "resource-walk", null);
write(xmlBuffer);
}
writeXMLFooter(null);
}
protected void addXMLHeader(StringBuffer xmlBuffer, String tagName) {
Map attrs = new SVNHashMap();
if (getUpdateRequest().isSendAll()) {
attrs.put(SEND_ALL_ATTR, Boolean.TRUE.toString());
}
DAVElementProperty rootElement = getDAVRequest().getRootElement();
SVNXMLUtil.addXMLHeader(xmlBuffer);
tagName = tagName == null ? rootElement.getName().getName() : tagName;
DAVXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName,
UPDATE_REPORT_NAMESPACES, attrs, xmlBuffer, true, false);
}
public void targetRevision(long revision) throws SVNException {
if (!isResourceWalk()) {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "target-revision",
SVNXMLUtil.XML_STYLE_SELF_CLOSING, REVISION_ATTR, String.valueOf(revision), null);
write(xmlBuffer);
}
}
public void openRoot(long revision) throws SVNException {
EditorEntry entry = new EditorEntry(false);
getEditorEntries().push(entry);
StringBuffer xmlBuffer = null;
if (isResourceWalk()) {
xmlBuffer = openResourceTag("", xmlBuffer);
} else {
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "open-directory", SVNXMLUtil.XML_STYLE_NORMAL, REVISION_ATTR, String.valueOf(revision), null);
}
if (getUpdateRequest().getTarget().length() == 0) {
addVersionURL(getRealPath(""), xmlBuffer);
}
if (isResourceWalk()) {
closeResourceTag(xmlBuffer);
}
write(xmlBuffer);
}
public void deleteEntry(String path, long revision) throws SVNException {
writeEntryTag("delete-entry", path);
}
public void absentDir(String path) throws SVNException {
if (!isResourceWalk()) {
writeEntryTag("absent-directory", path);
}
}
public void absentFile(String path) throws SVNException {
if (!isResourceWalk()) {
writeEntryTag("absent-file", path);
}
}
public void addDir(String path, String copyFromPath, long copyFromRevision) throws SVNException {
EditorEntry directoryEntry = new EditorEntry(true);
getEditorEntries().push(directoryEntry);
writeAddEntryTag(true, path, copyFromPath, copyFromRevision);
}
public void openDir(String path, long revision) throws SVNException {
EditorEntry directoryEntry = new EditorEntry(false);
getEditorEntries().push(directoryEntry);
writeEntryTag("open-directory", path, revision);
}
public void changeDirProperty(String name, SVNPropertyValue value) throws SVNException {
if (!isResourceWalk()) {
EditorEntry entry = (EditorEntry) getEditorEntries().peek();
changeProperties(entry, name, value);
}
}
public void closeDir() throws SVNException {
EditorEntry entry = (EditorEntry) getEditorEntries().pop();
closeEntry(entry, true, null);
}
public void addFile(String path, String copyFromPath, long copyFromRevision) throws SVNException {
setFileIsAdded(true);
writeAddEntryTag(false, path, copyFromPath, copyFromRevision);
}
public void openFile(String path, long revision) throws SVNException {
setFileIsAdded(false);
writeEntryTag("open-file", path, revision);
}
public void changeFileProperty(String path, String name, SVNPropertyValue value) throws SVNException {
if (!isResourceWalk()) {
changeProperties(getFileEditorEntry(), name, value);
}
}
public void closeFile(String path, String textChecksum) throws SVNException {
if (!getUpdateRequest().isSendAll() && !getFileEditorEntry().isAdded() && isFileTextChanged()) {
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "fetch-file", SVNXMLUtil.XML_STYLE_SELF_CLOSING, BASE_CHECKSUM_ATTR, getFileBaseChecksum(), null);
write(xmlBuffer);
}
closeEntry(getFileEditorEntry(), false, textChecksum);
getFileEditorEntry().refresh();
setFileTextChanged(false);
setFileBaseChecksum(null);
}
public SVNCommitInfo closeEdit() throws SVNException {
return null;
}
public void abortEdit() throws SVNException {
}
public void applyTextDelta(String path, String baseChecksum) throws SVNException {
setFileTextChanged(true);
setFileBaseChecksum(baseChecksum);
if (isResourceWalk()) {
return;
}
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "txdelta", SVNXMLUtil.XML_STYLE_NORMAL, null, null);
write(xmlBuffer);
}
public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException {
if (!isResourceWalk()) {
writeTextDeltaChunk(diffWindow);
}
return null;
}
public void textDeltaEnd(String path) throws SVNException {
if (!isResourceWalk()) {
textDeltaChunkEnd();
setWriteTextDeltaHeader(true);
StringBuffer xmlBuffer = SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "txdelta", null);
write(xmlBuffer);
}
}
private StringBuffer openResourceTag(String path, StringBuffer xmlBuffer) {
return SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "resource", SVNXMLUtil.XML_STYLE_NORMAL, PATH_ATTR, path, xmlBuffer);
}
private StringBuffer closeResourceTag(StringBuffer xmlBuffer) {
return SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "resource", xmlBuffer);
}
private void writeEntryTag(String tagName, String path) throws SVNException {
String directoryName = SVNPathUtil.tail(path);
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_SELF_CLOSING, NAME_ATTR, directoryName, null);
write(xmlBuffer);
}
private void writeEntryTag(String tagName, String path, long revision) throws SVNException {
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, SVNPathUtil.tail(path));
attrs.put(REVISION_ATTR, String.valueOf(revision));
StringBuffer xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_NORMAL, attrs, null);
addVersionURL(getRealPath(path), xmlBuffer);
write(xmlBuffer);
}
private void writeAddEntryTag(boolean isDirectory, String path, String copyFromPath, long copyFromRevision) throws SVNException {
StringBuffer xmlBuffer = null;
String realPath = getRealPath(path);
if (isResourceWalk()) {
String resourcePath = getUpdateRequest().getTarget() == null || getUpdateRequest().getTarget().length() == 0 ?
path : SVNPathUtil.append(getUpdateRequest().getTarget(), SVNPathUtil.removeHead(path));
xmlBuffer = openResourceTag(resourcePath, xmlBuffer);
} else {
Map attrs = new SVNHashMap();
attrs.put(NAME_ATTR, SVNPathUtil.tail(path));
if (isDirectory) {
long createdRevision = DAVServletUtil.getSafeCreatedRevision(myRevisionRoot, realPath);
String bcURL = DAVPathUtil.buildURI(getDAVResource().getResourceURI().getContext(), DAVResourceKind.BASELINE_COLL, createdRevision, realPath, false);
attrs.put(BC_URL_ATTR, bcURL);
}
if (copyFromPath != null) {
attrs.put(COPYFROM_PATH_ATTR, copyFromPath);
attrs.put(COPYFROM_REVISION_ATTR, String.valueOf(copyFromRevision));
}
String tagName = isDirectory ? "add-directory" : "add-file";
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, SVNXMLUtil.XML_STYLE_NORMAL, attrs, null);
}
addVersionURL(realPath, xmlBuffer);
if (isResourceWalk()) {
closeResourceTag(xmlBuffer);
}
write(xmlBuffer);
}
private void changeProperties(EditorEntry entry, String name, SVNPropertyValue value) throws SVNException {
//String quotedName = SVNEncodingUtil.xmlEncodeCDATA(name, true);
if (getUpdateRequest().isSendAll()) {
if (value != null) {
writePropertyTag("set-prop", name, value);
} else {
writeEntryTag("remove-prop", name);
}
} else {
if (SVNProperty.isEntryProperty(name)) {
if (SVNProperty.COMMITTED_REVISION.equals(name)) {
entry.setCommitedRevision(value.getString());
} else if (SVNProperty.COMMITTED_DATE.equals(name)) {
entry.setCommitedDate(value.getString());
} else if (SVNProperty.LAST_AUTHOR.equals(name)) {
entry.setLastAuthor(value.getString());
} else if (SVNProperty.LOCK_TOKEN.equals(name) && value == null) {
entry.addRemovedProperty(name);
}
return;
}
if (value == null) {
entry.addRemovedProperty(name);
} else {
entry.setHasChangedProperty(true);
}
}
}
private void closeEntry(EditorEntry entry, boolean isDirectory, String textCheckSum) throws SVNException {
if (isResourceWalk()) {
return;
}
StringBuffer xmlBuffer = new StringBuffer();
if (!entry.removedPropertiesCollectionIsEmpty() && !entry.isAdded()) {
for (Iterator iterator = entry.getRemovedProperies(); iterator.hasNext();) {
String name = (String) iterator.next();
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "remove-prop", SVNXMLUtil.XML_STYLE_SELF_CLOSING, NAME_ATTR, name, xmlBuffer);
}
}
if (!getUpdateRequest().isSendAll() && entry.hasChangedProperties() && !entry.isAdded()) {
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "fetch-props", SVNXMLUtil.XML_STYLE_SELF_CLOSING, null, xmlBuffer);
}
SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "prop", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
if (textCheckSum != null) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.SVN_DAV_PROPERTY_PREFIX, "md5-checksum", textCheckSum, xmlBuffer);
}
if (entry.getCommitedRevision() != null) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.VERSION_NAME.getName(), entry.getCommitedRevision(), xmlBuffer);
}
if (entry.getCommitedDate() != null) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CREATION_DATE.getName(), entry.getCommitedDate(), xmlBuffer);
}
if (entry.getLastAuthor() != null) {
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, DAVElement.CREATOR_DISPLAY_NAME.getName(), entry.getLastAuthor(), xmlBuffer);
}
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, "prop", xmlBuffer);
String tagName = entry.isAdded() ? "add-" : "open-";
tagName += isDirectory ? "directory" : "file";
SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_NAMESPACE_PREFIX, tagName, xmlBuffer);
write(xmlBuffer);
}
private StringBuffer addVersionURL(String path, StringBuffer xmlBuffer) {
long revision = DAVServletUtil.getSafeCreatedRevision(myRevisionRoot, path);
String url = DAVPathUtil.buildURI(getDAVResource().getResourceURI().getContext(), DAVResourceKind.VERSION, revision, path, false);
xmlBuffer = SVNXMLUtil.openXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "checked-in", SVNXMLUtil.XML_STYLE_NORMAL, null, xmlBuffer);
SVNXMLUtil.openCDataTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "href", url, xmlBuffer);
SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX, "checked-in", xmlBuffer);
return xmlBuffer;
}
private class EditorEntry {
boolean myAdded = false;
private String myCommitedRevision = null;
private String myCommitedDate = null;
private String myLastAuthor = null;
private Collection myRemovedProperties;
boolean myHasChangedProperties = false;
public EditorEntry(boolean isAdded) {
myAdded = isAdded;
}
private void setAdded(boolean isAdded) {
myAdded = isAdded;
}
private boolean isAdded() {
return myAdded;
}
private void setHasChangedProperty(boolean hasChangedProperties) {
myHasChangedProperties = hasChangedProperties;
}
private boolean hasChangedProperties() {
return myHasChangedProperties;
}
private void addRemovedProperty(String name) {
if (myRemovedProperties == null) {
myRemovedProperties = new ArrayList();
}
myRemovedProperties.add(name);
}
private boolean removedPropertiesCollectionIsEmpty() {
return myRemovedProperties == null || myRemovedProperties.isEmpty();
}
private Iterator getRemovedProperies() {
if (!removedPropertiesCollectionIsEmpty()) {
return myRemovedProperties.iterator();
}
return null;
}
private String getCommitedRevision() {
return myCommitedRevision;
}
private void setCommitedRevision(String commitedRevision) {
myCommitedRevision = commitedRevision;
}
private String getCommitedDate() {
return myCommitedDate;
}
private void setCommitedDate(String commitedDate) {
myCommitedDate = commitedDate;
}
private String getLastAuthor() {
return myLastAuthor;
}
private void setLastAuthor(String lastAuthor) {
myLastAuthor = lastAuthor;
}
private void refresh() {
myCommitedRevision = null;
myCommitedDate = null;
myLastAuthor = null;
myHasChangedProperties = false;
if (myRemovedProperties != null) {
myRemovedProperties.clear();
}
}
}
}

View File

@@ -0,0 +1,234 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @author TMate Software Ltd.
* @version 1.2.0
*/
public class DAVUpdateRequest extends DAVRequest {
private static final DAVElement TARGET_REVISION = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "target-revision");
private static final DAVElement SRC_PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "src-path");
private static final DAVElement DST_PATH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "dst-path");
private static final DAVElement UPDATE_TARGET = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "update-target");
private static final DAVElement DEPTH = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "depth");
private static final DAVElement RECURSIVE = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "recursive");
private static final DAVElement SEND_COPYFROM_ARGS = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "send-copyfrom-args");
private static final DAVElement IGNORE_ANCESTRY = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "ignore-ancestry");
private static final DAVElement TEXT_DELTAS = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "text-deltas");
private static final DAVElement RESOURCE_WALK = DAVElement.getElement(DAVElement.SVN_NAMESPACE, "resource-walk");
private boolean mySendAll = false;
private long myRevision = DAVResource.INVALID_REVISION;
private SVNURL mySrcURL = null;
private SVNURL myDstURL = null;
private String myTarget = "";
private boolean myTextDeltas = true;
private SVNDepth myDepth = SVNDepth.UNKNOWN;
private boolean mySendCopyFromArgs = false;
private boolean myDepthRequested = false;
private boolean myRecursiveRequested = false;
private boolean myIgnoreAncestry = false;
private boolean myResourceWalk = false;
private boolean myIsInitialized;
public boolean isSendAll() {
return mySendAll;
}
private void setSendAll(boolean sendAll) {
mySendAll = sendAll;
}
public long getRevision() {
return myRevision;
}
private void setRevision(long revision) {
myRevision = revision;
}
public SVNURL getSrcURL() {
return mySrcURL;
}
private void setSrcURL(SVNURL srcURL) {
mySrcURL = srcURL;
}
public SVNURL getDstURL() {
return myDstURL;
}
private void setDstURL(SVNURL dstURL) {
myDstURL = dstURL;
}
public String getTarget() {
return myTarget;
}
private void setTarget(String target) {
myTarget = target;
}
public boolean isTextDeltas() {
return myTextDeltas;
}
private void setTextDeltas(boolean textDeltas) {
myTextDeltas = textDeltas;
}
public SVNDepth getDepth() {
return myDepth;
}
private void setDepth(SVNDepth depth) {
myDepth = depth;
}
public boolean isSendCopyFromArgs() {
return mySendCopyFromArgs;
}
private void setSendCopyFromArgs(boolean sendCopyFromArgs) {
mySendCopyFromArgs = sendCopyFromArgs;
}
public boolean isDepthRequested() {
return myDepthRequested;
}
private void setDepthRequested(boolean depthRequested) {
myDepthRequested = depthRequested;
}
public boolean isRecursiveRequested() {
return myRecursiveRequested;
}
private void setRecursiveRequested(boolean recursiveRequested) {
myRecursiveRequested = recursiveRequested;
}
public boolean isIgnoreAncestry() {
return myIgnoreAncestry;
}
private void setIgnoreAncestry(boolean ignoreAncestry) {
myIgnoreAncestry = ignoreAncestry;
}
public boolean isResourceWalk() {
return myResourceWalk;
}
private void setResourceWalk(boolean resourceWalk) {
myResourceWalk = resourceWalk;
}
private boolean isInitialized() {
return myIsInitialized;
}
private void setInitialized(boolean isInitialized) {
myIsInitialized = isInitialized;
}
protected void init() throws SVNException {
if (!isInitialized()) {
String sendAll = getRootElementAttributeValue("send-all");
setSendAll(sendAll != null && Boolean.valueOf(sendAll).booleanValue());
DAVElementProperty rootElement = getRootElement();
for (Iterator iterator = rootElement.getChildren().iterator(); iterator.hasNext();) {
DAVElementProperty property = (DAVElementProperty) iterator.next();
DAVElement element = property.getName();
if (element == TARGET_REVISION) {
assertNullCData(element, property);
String value = property.getFirstValue(true);
try {
setRevision(Long.parseLong(value));
} catch (NumberFormatException nfe) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, nfe), SVNLogType.NETWORK);
}
} else if (element == SRC_PATH) {
assertNullCData(element, property);
String value = property.getFirstValue(false);
DAVPathUtil.testCanonical(value);
setSrcURL(SVNURL.parseURIEncoded(value));
} else if (element == DST_PATH) {
assertNullCData(element, property);
String value = property.getFirstValue(false);
DAVPathUtil.testCanonical(value);
setDstURL(SVNURL.parseURIEncoded(value));
} else if (element == UPDATE_TARGET) {
String value = property.getFirstValue(false);
DAVPathUtil.testCanonical(value);
setTarget(value);
} else if (element == DEPTH) {
assertNullCData(element, property);
String value = property.getFirstValue(true);
setDepth(SVNDepth.fromString(value));
setDepthRequested(true);
} else if (element == SEND_COPYFROM_ARGS) {
assertNullCData(element, property);
setSendCopyFromArgs("no".equals(property.getFirstValue(true)));
} else if (element == RECURSIVE && !isDepthRequested()) {
assertNullCData(element, property);
String value = property.getFirstValue(true);
setDepth(SVNDepth.fromRecurse(!"no".equals(value)));
setRecursiveRequested(true);
} else if (element == IGNORE_ANCESTRY) {
assertNullCData(element, property);
String value = property.getFirstValue(true);
setIgnoreAncestry(!"no".equals(value));
} else if (element == TEXT_DELTAS) {
assertNullCData(element, property);
String value = property.getFirstValue(true);
setTextDeltas(!"no".equals(value));
} else if (element == RESOURCE_WALK) {
assertNullCData(element, property);
String value = property.getFirstValue(true);
setResourceWalk(!"no".equals(value));
}
}
if (!isDepthRequested() && !isRecursiveRequested() && (getDepth() == SVNDepth.UNKNOWN)) {
setDepth(SVNDepth.INFINITY);
}
if (getSrcURL() == null) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED,
"The request did not contain the '<src-path>' element.\nThis may indicate that your client is too old."), SVNLogType.NETWORK);
}
if (!isSendAll()) {
setTextDeltas(false);
}
setInitialized(true);
}
}
}

View File

@@ -0,0 +1,265 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVIFHeader;
import org.tmatesoft.svn.core.internal.server.dav.DAVIFState;
import org.tmatesoft.svn.core.internal.server.dav.DAVIFStateType;
import org.tmatesoft.svn.core.internal.server.dav.DAVLock;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVPathUtil;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVValidateWalker implements IDAVResourceWalkHandler {
public DAVResponse handleResource(DAVResponse response, DAVResource resource, DAVLockInfoProvider lockInfoProvider, LinkedList ifHeaders,
int flags, DAVLockScope lockScope, CallType callType) throws DAVException {
DAVException exception = null;
try {
validateResourceState(ifHeaders, resource, lockInfoProvider, lockScope, flags);
return response;
} catch (DAVException e) {
exception = e;
}
//TODO: I'm not sure what resources we should compare here
if (DAVServlet.isHTTPServerError(exception.getResponseCode())) {
throw exception;
}
DAVResponse resp = new DAVResponse(null, resource.getResourceURI().getRequestURI(), response, null, exception.getResponseCode());
return resp;
}
public void validateResourceState(LinkedList ifHeaders, DAVResource resource, DAVLockInfoProvider provider, DAVLockScope lockScope, int flags) throws DAVException {
DAVLock lock = null;
if (provider != null) {
try {
lock = provider.getLock(resource);
} catch (DAVException dave) {
throw new DAVException("The locks could not be queried for verification against a possible \"If:\" header.", null,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, SVNLogType.NETWORK, Level.FINE, dave, null, null, 0, null);
}
}
boolean seenLockToken = false;
if (lockScope == DAVLockScope.EXCLUSIVE) {
if (lock != null) {
throw new DAVException("Existing lock(s) on the requested resource prevent an exclusive lock.", ServletDAVHandler.SC_HTTP_LOCKED, 0);
}
seenLockToken = true;
} else if (lockScope == DAVLockScope.SHARED) {
if (lock.getScope() == DAVLockScope.EXCLUSIVE) {
throw new DAVException("The requested resource is already locked exclusively.", ServletDAVHandler.SC_HTTP_LOCKED, 0);
}
seenLockToken = true;
} else {
seenLockToken = lock == null;
}
if (ifHeaders == null || ifHeaders.isEmpty()) {
if (seenLockToken) {
return;
}
throw new DAVException("This resource is locked and an \"If:\" header was not supplied to allow access to the resource.",
ServletDAVHandler.SC_HTTP_LOCKED, 0);
}
DAVIFHeader ifHeader = (DAVIFHeader) ifHeaders.getFirst();
if (lock == null && ifHeader.isDummyHeader()) {
if ((flags & ServletDAVHandler.DAV_VALIDATE_IS_PARENT) != 0) {
return;
}
throw new DAVException("The locktoken specified in the \"Lock-Token:\" header is invalid because this resource has no outstanding locks.",
HttpServletResponse.SC_BAD_REQUEST, 0);
}
String eTag = resource.getETag();
String uri = DAVPathUtil.dropTraillingSlash(resource.getResourceURI().getRequestURI());
int numThatAppy = 0;
String reason = null;
Iterator ifHeadersIter = ifHeaders.iterator();
for (;ifHeadersIter.hasNext();) {
ifHeader = (DAVIFHeader) ifHeadersIter.next();
if (ifHeader.getURI() != null && !uri.equals(ifHeader.getURI())) {
continue;
}
++numThatAppy;
LinkedList stateList = ifHeader.getStateList();
boolean doContinue = false;
for (Iterator stateListIter = stateList.iterator(); stateListIter.hasNext();) {
DAVIFState state = (DAVIFState) stateListIter.next();
if (state.getType() == DAVIFStateType.IF_ETAG) {
String currentETag = null;
String givenETag = null;
String stateETag = state.getETag();
if (stateETag.startsWith("W/")) {
givenETag = stateETag.substring(2);
} else {
givenETag = stateETag;
}
if (eTag.startsWith("W/")) {
currentETag = eTag.substring(2);
} else {
currentETag = eTag;
}
boolean eTagsDoNotMatch = !givenETag.equals(currentETag);
if (state.getCondition() == DAVIFState.IF_CONDITION_NORMAL && eTagsDoNotMatch) {
reason = "an entity-tag was specified, but the resource's actual ETag does not match.";
doContinue = true;
break;
} else if (state.getCondition() == DAVIFState.IF_CONDITION_NOT && !eTagsDoNotMatch) {
reason = "an entity-tag was specified using the \"Not\" form, but the resource's actual ETag matches the provided entity-tag.";
doContinue = true;
break;
}
} else if (state.getType() == DAVIFStateType.IF_OPAQUE_LOCK) {
if (provider == null) {
if (state.getCondition() == DAVIFState.IF_CONDITION_NOT) {
continue;
}
reason = "a State-token was supplied, but a lock database is not available for to provide the required lock.";
doContinue = true;
break;
}
boolean matched = false;
if (lock != null) {
if (!lock.getLockToken().equals(state.getLockToken())) {
continue;
}
seenLockToken = true;
if (state.getCondition() == DAVIFState.IF_CONDITION_NOT) {
reason = "a State-token was supplied, which used a \"Not\" condition. The State-token was found in the locks on this resource";
doContinue = true;
break;
}
String lockAuthUser = lock.getAuthUser();
String requestUser = resource.getUserName();
if (lockAuthUser != null && (requestUser == null || !lockAuthUser.equals(requestUser))) {
throw new DAVException("User \"{0}\" submitted a locktoken created by user \"{1}\".",
new Object[] { requestUser, lockAuthUser }, HttpServletResponse.SC_FORBIDDEN, 0);
}
matched = true;
}
if (!matched && state.getCondition() == DAVIFState.IF_CONDITION_NORMAL) {
reason = "a State-token was supplied, but it was not found in the locks on this resource.";
doContinue = true;
break;
}
} else if (state.getType() == DAVIFStateType.IF_UNKNOWN) {
if (state.getCondition() == DAVIFState.IF_CONDITION_NORMAL) {
reason = "an unknown state token was supplied";
doContinue = true;
break;
}
}
}
if (doContinue) {
continue;
}
if (seenLockToken) {
return;
}
break;
}
if (!ifHeadersIter.hasNext()) {
if (numThatAppy == 0) {
if (seenLockToken) {
return;
}
if (findSubmittedLockToken(ifHeaders, lock)) {
return;
}
throw new DAVException("This resource is locked and the \"If:\" header did not specify one of the locktokens for this resource's lock(s).",
ServletDAVHandler.SC_HTTP_LOCKED, 0);
}
ifHeader = (DAVIFHeader) ifHeaders.getFirst();
if (ifHeader.isDummyHeader()) {
throw new DAVException("The locktoken specified in the \"Lock-Token:\" header did not specify one of this resource's locktoken(s).",
HttpServletResponse.SC_BAD_REQUEST, 0);
}
if (reason == null) {
throw new DAVException("The preconditions specified by the \"If:\" header did not match this resource.",
HttpServletResponse.SC_PRECONDITION_FAILED, 0);
}
throw new DAVException("The precondition(s) specified by the \"If:\" header did not match this resource. At least one failure is because: {0}",
new Object[] { reason }, HttpServletResponse.SC_PRECONDITION_FAILED, 0);
}
if (findSubmittedLockToken(ifHeaders, lock)) {
return;
}
if (ifHeader.isDummyHeader()) {
throw new DAVException("The locktoken specified in the \"Lock-Token:\" header did not specify one of this resource's locktoken(s).",
HttpServletResponse.SC_BAD_REQUEST, 0);
}
throw new DAVException("This resource is locked and the \"If:\" header did not specify one of the locktokens for this resource's lock(s).",
ServletDAVHandler.SC_HTTP_LOCKED, 1);
}
private boolean findSubmittedLockToken(LinkedList ifHeaders, DAVLock lock) {
for (Iterator ifHeadersIter = ifHeaders.iterator(); ifHeadersIter.hasNext();) {
DAVIFHeader ifHeader = (DAVIFHeader) ifHeadersIter.next();
LinkedList ifStates = ifHeader.getStateList();
for (Iterator ifStatesIter = ifStates.iterator(); ifStatesIter.hasNext();) {
DAVIFState ifState = (DAVIFState) ifStatesIter.next();
if (ifState.getType() == DAVIFStateType.IF_OPAQUE_LOCK) {
String lockToken = lock.getLockToken();
String stateLockToken = ifState.getLockToken();
if (lockToken.equals(stateLockToken)) {
return true;
}
}
}
}
return false;
}
}

View File

@@ -0,0 +1,20 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class DAVWalkResource {
}

View File

@@ -0,0 +1,38 @@
/*
* ====================================================================
* Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import java.util.LinkedList;
import org.tmatesoft.svn.core.internal.server.dav.DAVException;
import org.tmatesoft.svn.core.internal.server.dav.DAVLockScope;
import org.tmatesoft.svn.core.internal.server.dav.DAVResource;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public interface IDAVResourceWalkHandler {
public DAVResponse handleResource(DAVResponse response, DAVResource resource, DAVLockInfoProvider lockInfoProvider,
LinkedList ifHeaders, int flags, DAVLockScope lockScope, CallType callType) throws DAVException;
public static class CallType {
public static final CallType MEMBER = new CallType();
public static final CallType COLLECTION = new CallType();
public static final CallType LOCKNULL = new CallType();
private CallType() {
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* ====================================================================
* Copyright (c) 2004-2009 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.server.dav.handlers;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
/**
* @version 1.2.0
* @author TMate Software Ltd.
*/
public class LivePropertySpecification {
private DAVElement myPropertyName;
private boolean myIsWritable;
private boolean myIsSVNSupported;
public LivePropertySpecification(DAVElement propertyName, boolean isWritable, boolean isSVNSupported) {
myIsWritable = isWritable;
myPropertyName = propertyName;
myIsSVNSupported = isSVNSupported;
}
public DAVElement getPropertyName() {
return myPropertyName;
}
public boolean isWritable() {
return myIsWritable;
}
public boolean isSVNSupported() {
return myIsSVNSupported;
}
}

Some files were not shown because too many files have changed in this diff Show More