mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 08:55:44 +01:00
added SvnDAVServlet to scm-svn-plugin
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
1
pom.xml
1
pom.xml
@@ -36,6 +36,7 @@
|
||||
</prerequisites>
|
||||
|
||||
<modules>
|
||||
<module>third-party</module>
|
||||
<module>scm-core</module>
|
||||
<module>scm-cli</module>
|
||||
<module>scm-web-api</module>
|
||||
|
||||
@@ -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
22
third-party/pom.xml
vendored
Normal 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
34
third-party/svnkit-dav/pom.xml
vendored
Normal 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>
|
||||
213
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/io/dav/DAVElement.java
vendored
Normal file
213
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/io/dav/DAVElement.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
418
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/io/fs/FSRepositoryUtil.java
vendored
Normal file
418
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/io/fs/FSRepositoryUtil.java
vendored
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
186
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVConfig.java
vendored
Normal file
186
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVConfig.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
67
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVDepth.java
vendored
Normal file
67
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVDepth.java
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
160
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVException.java
vendored
Normal file
160
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVException.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
52
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVIFHeader.java
vendored
Normal file
52
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVIFHeader.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
52
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVIFState.java
vendored
Normal file
52
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVIFState.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
81
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVLock.java
vendored
Normal file
81
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVLock.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
25
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVLockType.java
vendored
Normal file
25
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVLockType.java
vendored
Normal 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() {
|
||||
}
|
||||
}
|
||||
262
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVPathUtil.java
vendored
Normal file
262
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVPathUtil.java
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
631
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVResource.java
vendored
Normal file
631
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVResource.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
349
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVResourceURI.java
vendored
Normal file
349
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVResourceURI.java
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
305
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVServlet.java
vendored
Normal file
305
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVServlet.java
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
440
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVServletUtil.java
vendored
Normal file
440
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVServletUtil.java
vendored
Normal 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() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
42
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVURIInfo.java
vendored
Normal file
42
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVURIInfo.java
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
185
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVXMLUtil.java
vendored
Normal file
185
third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVXMLUtil.java
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user