Replace static mercurial permission handling

Replace our own hg permission handling with the default hg permission which is controlled by the `web` config
This commit is contained in:
Eduard Heimbuch
2023-04-03 09:47:15 +02:00
committed by SCM-Manager
parent e679dac94d
commit 026ffa18fd
8 changed files with 53 additions and 418 deletions

View File

@@ -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;

View File

@@ -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<String> createArgs(HgConfig config) {
private List<String> createArgs(Repository repository, HgConfig config) {
List<String> 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

View File

@@ -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<String> READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE");
public class HgPermissionFilter extends PermissionFilter {
private static final Set<String> 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());
}
}

View File

@@ -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;
}
}

View File

@@ -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<String> 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<String> 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<String> commands = commandsOf(request);
boolean write = isWriteRequest(commands);
LOG.trace("mercurial request {} is write: {}", commands, write);
return write;
}
@VisibleForTesting
static boolean isWriteRequest(List<String> commands) {
return !READ_COMMANDS.containsAll(commands);
}
@VisibleForTesting
static List<String> commandsOf(HttpServletRequest request) {
List<String> 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) {

View File

@@ -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 <a href="https://goo.gl/poascp">Issue #970</a>
*/
@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));
}
}

View File

@@ -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<String> headers = Lists.newArrayList();
StringBuilder vary = new StringBuilder();
for ( int i=0; i<values.length; i++ ) {
String header = "X-HgArg-" + (i+1);
if (i>0) {
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);
}
}

View File

@@ -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<String> cmdList = Lists.newArrayList(commands);
assertTrue(WireProtocol.isWriteRequest(cmdList));
}
private void assertIsReadRequest(String... commands) {
List<String> cmdList = Lists.newArrayList(commands);
assertFalse(WireProtocol.isWriteRequest(cmdList));
}
@Test
public void testGetCommandsOf() {
expectQueryCommand("capabilities", "cmd=capabilities");