diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index 9cfa95c1d5..dd586881ff 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -98,7 +98,7 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator */ @Override public void service(HttpServletRequest request, - HttpServletResponse response, Repository repository) + HttpServletResponse response, Repository repository) throws IOException, ServletException { Subject subject = SecurityUtils.getSubject(); @@ -121,13 +121,13 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator getActionAsString(writeRequest), repository.getName(), getUserName(subject)); - sendAccessDenied(request, response, subject); + sendAccessDenied(request, response); } } catch (ScmSecurityException | AuthorizationException ex) { logger.warn("user " + subject.getPrincipal() + " has not enough permissions", ex); - sendAccessDenied(request, response, subject); + sendAccessDenied(request, response); } } @@ -142,7 +142,7 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator * @throws IOException */ protected void sendNotEnoughPrivilegesError(HttpServletRequest request, - HttpServletResponse response) + HttpServletResponse response) throws IOException { response.sendError(HttpServletResponse.SC_FORBIDDEN); @@ -158,7 +158,7 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator * @throws IOException */ protected void sendUnauthorizedError(HttpServletRequest request, - HttpServletResponse response) + HttpServletResponse response) throws IOException { HttpUtil.sendUnauthorized(response, configuration.getRealmDescription()); @@ -169,12 +169,11 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator * * @param request current http request object * @param response current http response object - * @param subject user subject * * @throws IOException */ private void sendAccessDenied(HttpServletRequest request, - HttpServletResponse response, Subject subject) + HttpServletResponse response) throws IOException { if (!Authentications.isAuthenticatedSubjectAnonymous()) @@ -233,7 +232,7 @@ public abstract class PermissionFilter extends ScmProviderHttpServletDecorator * * @return true if the current user has the required permissions */ - private boolean hasPermission(Repository repository, boolean writeRequest) + public static boolean hasPermission(Repository repository, boolean writeRequest) { boolean permitted; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index fcb256b528..7ed011fa98 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -31,19 +31,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.HgEnvironmentBuilder; -import sonia.scm.repository.HgExtensions; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgConfigResolver; +import sonia.scm.repository.HgEnvironmentBuilder; +import sonia.scm.repository.HgExtensions; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.RepositoryRequestListenerUtil; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.cgi.CGIExecutor; import sonia.scm.web.cgi.CGIExecutorFactory; - -import javax.annotation.Nonnull; import sonia.scm.web.cgi.EnvList; +import javax.annotation.Nonnull; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -147,12 +147,12 @@ public class HgCGIServlet extends HttpServlet implements ScmProviderHttpServlet HgConfig config = configResolver.resolve(repository); executor.setWorkDirectory(config.getDirectory()); - executor.setArgs(createArgs(config)); + executor.setArgs(createArgs(repository, config)); executor.execute(config.getHgBinary()); } @Nonnull - private List createArgs(HgConfig config) { + private List createArgs(Repository repository, HgConfig config) { List args = new ArrayList<>(); config(args, "extensions.cgiserve", extension.getAbsolutePath()); @@ -160,9 +160,19 @@ public class HgCGIServlet extends HttpServlet implements ScmProviderHttpServlet config(args, "hooks.pretxnchangegroup.scm", String.format("python:%s:pre_hook", hooks)); config(args, "hooks.changegroup.scm", String.format("python:%s:post_hook", hooks)); + if (RepositoryPermissions.push(repository).isPermitted()) { + config(args, "web.allow_push", "*"); + } else { + config(args, "web.deny_push", "*"); + } + + if(RepositoryPermissions.pull(repository).isPermitted()) { + config(args, "web.allow_read", "*"); + } else { + config(args, "web.deny_read", "*"); + } + config(args, "web.push_ssl", "false"); - config(args, "web.allow_read", "*"); - config(args, "web.allow_push", "*"); // enable experimental httppostargs protocol of mercurial // Issue 970: https://goo.gl/poascp diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index 3f642952da..56a0f65e60 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -21,40 +21,34 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableSet; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; -import sonia.scm.repository.HgRepositoryHandler; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; -import java.util.Set; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Set; /** * Permission filter for mercurial repositories. - * + * * @author Sebastian Sdorra */ -public class HgPermissionFilter extends PermissionFilter -{ - - private static final Set READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE"); +public class HgPermissionFilter extends PermissionFilter { + + private static final Set READ_METHODS = Set.of("GET", "HEAD", "OPTIONS", "TRACE"); private final HgRepositoryHandler repositoryHandler; - public HgPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate, HgRepositoryHandler repositoryHandler) - { + public HgPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate, HgRepositoryHandler repositoryHandler) { super(configuration, delegate); this.repositoryHandler = repositoryHandler; } @@ -73,10 +67,9 @@ public class HgPermissionFilter extends PermissionFilter } @Override - public boolean isWriteRequest(HttpServletRequest request) - { + public boolean isWriteRequest(HttpServletRequest request) { if (isHttpPostArgsEnabled()) { - return isHttpPostArgsWriteRequest(request); + return true; } return isDefaultWriteRequest(request); } @@ -85,14 +78,7 @@ public class HgPermissionFilter extends PermissionFilter return repositoryHandler.getConfig().isEnableHttpPostArgs(); } - private boolean isHttpPostArgsWriteRequest(HttpServletRequest request) { - return WireProtocol.isWriteRequest(request); - } - private boolean isDefaultWriteRequest(HttpServletRequest request) { - if (READ_METHODS.contains(request.getMethod())) { - return WireProtocol.isWriteRequest(request); - } - return true; + return !READ_METHODS.contains(request.getMethod()); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java index c6b6458d92..cd73edd94b 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java @@ -24,7 +24,6 @@ package sonia.scm.web; -import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; @@ -35,13 +34,9 @@ import javax.inject.Inject; @Extension public class HgPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { - private final ScmConfiguration configuration; - private final HgRepositoryHandler repositoryHandler; - @Inject - public HgPermissionFilterFactory(ScmConfiguration configuration, HgRepositoryHandler repositoryHandler) { - this.configuration = configuration; - this.repositoryHandler = repositoryHandler; + public HgPermissionFilterFactory() { + // empty } @Override @@ -51,6 +46,6 @@ public class HgPermissionFilterFactory implements ScmProviderHttpServletDecorato @Override public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { - return new HgPermissionFilter(configuration, delegate,repositoryHandler); + return delegate; } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java index facd8cc8e7..acb5f0a994 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/WireProtocol.java @@ -29,14 +29,20 @@ import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.base.Throwables; -import com.google.common.collect.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; import sonia.scm.util.HttpUtil; import javax.servlet.http.HttpServletRequest; import java.io.IOException; -import java.util.*; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; /** * WireProtocol provides methods for handling the mercurial wire protocol. @@ -45,52 +51,9 @@ import java.util.*; */ public final class WireProtocol { - private static final Logger LOG = LoggerFactory.getLogger(WireProtocol.class); - - private static final Set READ_COMMANDS = ImmutableSet.of( - "batch", "between", "branchmap", "branches", "capabilities", "changegroup", "changegroupsubset", "clonebundles", - "getbundle", "heads", "hello", "listkeys", "lookup", "known", "stream_out", - // could not find lheads in the wireprotocol description but mercurial 4.5.2 uses it for clone - "lheads", - // For HG Evolve Extension - "evoext_obshashrange_v1" - ); - - private static final Set WRITE_COMMANDS = ImmutableSet.of( - "pushkey", "unbundle" - ); - private WireProtocol() { } - /** - * Returns {@code true} if the request is a write request. The method will always return {@code true}, expect for the - * following cases: - * - * - no command was specified with the request (is required for the hgweb ui) - * - the command in the query string was found in the list of read request - * - if query string contains the batch command, then all commands specified in X-HgArg headers must be - * in the list of read requests - * - in case of enabled HttpPostArgs protocol and query string container the batch command, the header X-HgArgs-Post - * is read and the commands which are specified in the body from 0 to the value of X-HgArgs-Post must be in the list - * of read requests - * - * @param request http request - * - * @return {@code true} for write requests. - */ - public static boolean isWriteRequest(HttpServletRequest request) { - List commands = commandsOf(request); - boolean write = isWriteRequest(commands); - LOG.trace("mercurial request {} is write: {}", commands, write); - return write; - } - - @VisibleForTesting - static boolean isWriteRequest(List commands) { - return !READ_COMMANDS.containsAll(commands); - } - @VisibleForTesting static List commandsOf(HttpServletRequest request) { List listOfCmds = Lists.newArrayList(); @@ -126,7 +89,7 @@ public final class WireProtocol { byte[] bytes = hgRequest.getInputStream().readAndCapture(hgArgsPostSize); // we use iso-8859-1 for encoding, because the post args are normally http headers which are using iso-8859-1 // see https://tools.ietf.org/html/rfc7230#section-3.2.4 - String hgArgs = new String(bytes, Charsets.ISO_8859_1); + String hgArgs = new String(bytes, StandardCharsets.ISO_8859_1); String decoded = decodeValue(hgArgs); parseHgCommandHeader(listOfCmds, decoded); } catch (IOException ex) { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java index 24f3d7c178..f331175c54 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgPermissionFilterTest.java @@ -29,44 +29,27 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.*; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.HgGlobalConfig; import sonia.scm.repository.HgRepositoryHandler; -import sonia.scm.repository.RepositoryProvider; import javax.servlet.http.HttpServletRequest; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.*; -import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES; -import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.BOOKMARKS; -import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.PHASES; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; -/** - * Unit tests for {@link HgPermissionFilter}. - * - * @author Sebastian Sdorra - */ @RunWith(MockitoJUnitRunner.class) public class HgPermissionFilterTest { @Mock private HttpServletRequest request; - @Mock - private ScmConfiguration configuration; - - @Mock - private RepositoryProvider repositoryProvider; - @Mock private HgRepositoryHandler hgRepositoryHandler; - private WireProtocolRequestMockFactory wireProtocol = new WireProtocolRequestMockFactory("/scm/hg/repo"); - @InjectMocks private HgPermissionFilter filter; @@ -75,9 +58,6 @@ public class HgPermissionFilterTest { when(hgRepositoryHandler.getConfig()).thenReturn(new HgGlobalConfig()); } - /** - * Tests {@link HgPermissionFilter#wrapRequestIfRequired(HttpServletRequest)}. - */ @Test public void testWrapRequestIfRequired() { assertSame(request, filter.wrapRequestIfRequired(request)); @@ -88,140 +68,4 @@ public class HgPermissionFilterTest { assertThat(filter.wrapRequestIfRequired(request), is(instanceOf(HgServletRequest.class))); } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)}. - */ - @Test - public void testIsWriteRequest() { - // read methods - assertFalse(isWriteRequest("GET")); - assertFalse(isWriteRequest("HEAD")); - assertFalse(isWriteRequest("TRACE")); - assertFalse(isWriteRequest("OPTIONS")); - - // write methods - assertTrue(isWriteRequest("POST")); - assertTrue(isWriteRequest("PUT")); - assertTrue(isWriteRequest("DELETE")); - assertTrue(isWriteRequest("KA")); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with enabled httppostargs option. - */ - @Test - public void testIsWriteRequestWithEnabledHttpPostArgs() { - HgGlobalConfig config = new HgGlobalConfig(); - config.setEnableHttpPostArgs(true); - when(hgRepositoryHandler.getConfig()).thenReturn(config); - - assertFalse(isWriteRequest("POST")); - assertFalse(isWriteRequest("POST", "heads")); - assertTrue(isWriteRequest("POST", "unbundle")); - } - - private boolean isWriteRequest(String method) { - return isWriteRequest(method, "capabilities"); - } - - private boolean isWriteRequest(String method, String command) { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getQueryString()).thenReturn("cmd=" + command); - when(request.getMethod()).thenReturn(method); - return filter.isWriteRequest(request); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a - * fresh clone of a repository. - */ - @Test - public void testIsWriteRequestWithClone() { - assertIsReadRequest(wireProtocol.capabilities()); - assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); - assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES)); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a - * push of a single changeset. - */ - @Test - public void testIsWriteRequestWithSingleChangesetPush() { - assertIsReadRequest(wireProtocol.capabilities()); - assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2"))); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); - assertIsWriteRequest(wireProtocol.unbundle(261L, "686173686564+6768033e216468247bd031a0a2d9876d79818f8f")); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsWriteRequest(wireProtocol.pushkey("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2&namespace=phases&new=0&old=1")); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a - * push to a single changeset. - */ - @Test - public void testIsWriteRequestWithMultipleChangesetsPush() { - assertIsReadRequest(wireProtocol.capabilities()); - assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98"))); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); - assertIsReadRequest(wireProtocol.branchmap()); - assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); - assertIsWriteRequest(wireProtocol.unbundle(746L, "686173686564+95373ca7cd5371cb6c49bb755ee451d9ec585845")); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsWriteRequest(wireProtocol.pushkey("ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1")); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a - * push of multiple branches to a new repository. - */ - @Test - public void testIsWriteRequestWithMutlipleBranchesToNewRepositoryPush() { - assertIsReadRequest(wireProtocol.capabilities()); - assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98"))); - assertIsReadRequest(wireProtocol.known("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2+187ddf37e237c370514487a0bb1a226f11a780b3+b5914611f84eae14543684b2721eec88b0edac12+8b63a323606f10c86b30465570c2574eb7a3a989")); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); - assertIsWriteRequest(wireProtocol.unbundle(913L, "686173686564+6768033e216468247bd031a0a2d9876d79818f8f")); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsWriteRequest(wireProtocol.pushkey("ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1")); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a - * push of a bookmark. - */ - @Test - public void testIsWriteRequestWithBookmarkPush() { - assertIsReadRequest(wireProtocol.capabilities()); - assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98"))); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS)); - assertIsReadRequest(wireProtocol.listkeys(PHASES)); - assertIsWriteRequest(wireProtocol.pushkey("markone&namespace=bookmarks&new=ef5993bb4abb32a0565c347844c6d939fc4f4b98&old=")); - } - - /** - * Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a write request hidden in a batch GET - * request. - * - * @see Issue #970 - */ - @Test - public void testIsWriteRequestWithBookmarkPushInABatch() { - assertIsWriteRequest(wireProtocol.batch("pushkey key=markthree,namespace=bookmarks,new=187ddf37e237c370514487a0bb1a226f11a780b3,old=")); - } - - private void assertIsReadRequest(HttpServletRequest request) { - assertFalse(filter.isWriteRequest(request)); - } - - private void assertIsWriteRequest(HttpServletRequest request) { - assertTrue(filter.isWriteRequest(request)); - } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java deleted file mode 100644 index 9864c21b45..0000000000 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolRequestMockFactory.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020-present Cloudogu GmbH and Contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sonia.scm.web; - -import com.google.common.collect.Lists; - -import javax.servlet.http.HttpServletRequest; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class WireProtocolRequestMockFactory { - - public enum Namespace { - PHASES, BOOKMARKS; - } - - public static final String CMDS_HEADS_KNOWN_NODES = "heads+%3Bknown+nodes%3D"; - - private String repositoryPath; - - public WireProtocolRequestMockFactory(String repositoryPath) { - this.repositoryPath = repositoryPath; - } - - public HttpServletRequest capabilities() { - return base("GET", "cmd=capabilities"); - } - - public HttpServletRequest listkeys(Namespace namespace) { - HttpServletRequest request = base("GET", "cmd=capabilities"); - header(request, "vary", "X-HgArg-1"); - header(request, "x-hgarg-1", namespaceValue(namespace)); - return request; - } - - public HttpServletRequest branchmap() { - return base("GET", "cmd=branchmap"); - } - - public HttpServletRequest batch(String... args) { - HttpServletRequest request = base("GET", "cmd=batch"); - args(request, "cmds", args); - return request; - } - - public HttpServletRequest unbundle(long contentLength, String... heads) { - HttpServletRequest request = base("POST", "cmd=unbundle"); - header(request, "Content-Length", String.valueOf(contentLength)); - args(request, "heads", heads); - return request; - } - - public HttpServletRequest pushkey(String... keys) { - HttpServletRequest request = base("POST", "cmd=pushkey"); - args(request, "key", keys); - return request; - } - - public HttpServletRequest known(String... nodes) { - HttpServletRequest request = base("GET", "cmd=known"); - args(request, "nodes", nodes); - return request; - } - - private void args(HttpServletRequest request, String prefix, String[] values) { - List headers = Lists.newArrayList(); - - StringBuilder vary = new StringBuilder(); - for ( int i=0; i0) { - vary.append(","); - } - - vary.append(header); - headers.add(header); - - header(request, header, prefix + "=" + values[i]); - } - header(request, "Vary", vary.toString()); - - when(request.getHeaderNames()).thenReturn(Collections.enumeration(headers)); - } - - private HttpServletRequest base(String method, String queryStringValue) { - HttpServletRequest request = mock(HttpServletRequest.class); - - when(request.getMethod()).thenReturn(method); - - queryString(request, queryStringValue); - - header(request, "Accept", "application/mercurial-0.1"); - header(request, "Accept-Encoding", "identity"); - header(request, "User-Agent", "mercurial/proto-1.0 (Mercurial 4.3.1)"); - return request; - } - - private void queryString(HttpServletRequest request, String queryString) { - when(request.getQueryString()).thenReturn(queryString); - } - - private void header(HttpServletRequest request, String header, String value) { - when(request.getHeader(header)).thenReturn(value); - } - - private String namespaceValue(Namespace namespace) { - return "namespace=" + namespace.toString().toLowerCase(Locale.ENGLISH); - } - -} diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java index 92449ce875..eeefbdcaf6 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java @@ -51,31 +51,6 @@ public class WireProtocolTest { @Mock private HttpServletRequest request; - @Test - public void testIsWriteRequestOnPost() { - assertIsWriteRequest("capabilities", "unbundle"); - } - - @Test - public void testIsWriteRequest() { - assertIsWriteRequest("unbundle"); - assertIsWriteRequest("capabilities", "unbundle"); - assertIsWriteRequest("capabilities", "postkeys"); - assertIsReadRequest(); - assertIsReadRequest("capabilities"); - assertIsReadRequest("capabilities", "branches", "branchmap"); - } - - private void assertIsWriteRequest(String... commands) { - List cmdList = Lists.newArrayList(commands); - assertTrue(WireProtocol.isWriteRequest(cmdList)); - } - - private void assertIsReadRequest(String... commands) { - List cmdList = Lists.newArrayList(commands); - assertFalse(WireProtocol.isWriteRequest(cmdList)); - } - @Test public void testGetCommandsOf() { expectQueryCommand("capabilities", "cmd=capabilities");