mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-17 10:41:06 +01:00
Handle missing request scope for url computation
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package sonia.scm.repository.spi;
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.api.v2.resources.ScmPathInfoStore;
|
import sonia.scm.api.v2.resources.ScmPathInfoStore;
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
@@ -11,9 +13,15 @@ import javax.servlet.ServletException;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static java.util.Optional.empty;
|
||||||
|
import static java.util.Optional.of;
|
||||||
|
|
||||||
public abstract class InitializingHttpScmProtocolWrapper {
|
public abstract class InitializingHttpScmProtocolWrapper {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class);
|
||||||
|
|
||||||
private final Provider<? extends ScmProviderHttpServlet> delegateProvider;
|
private final Provider<? extends ScmProviderHttpServlet> delegateProvider;
|
||||||
private final Provider<? extends PermissionFilter> permissionFilterProvider;
|
private final Provider<? extends PermissionFilter> permissionFilterProvider;
|
||||||
private final Provider<ScmPathInfoStore> uriInfoStore;
|
private final Provider<ScmPathInfoStore> uriInfoStore;
|
||||||
@@ -38,11 +46,24 @@ public abstract class InitializingHttpScmProtocolWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String computeBasePath() {
|
private String computeBasePath() {
|
||||||
if (uriInfoStore.get() != null && uriInfoStore.get().get() != null) {
|
return getPathFromScmPathInfoIfAvailable().orElse(getPathFromConfiguration());
|
||||||
return uriInfoStore.get().get().getApiRestUri().resolve("../..").toASCIIString();
|
|
||||||
} else {
|
|
||||||
return scmConfiguration.getBaseUrl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<String> getPathFromScmPathInfoIfAvailable() {
|
||||||
|
try {
|
||||||
|
ScmPathInfoStore scmPathInfoStore = uriInfoStore.get();
|
||||||
|
if (scmPathInfoStore != null && scmPathInfoStore.get() != null) {
|
||||||
|
return of(scmPathInfoStore.get().getApiRestUri().resolve("../..").toASCIIString());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("could not get ScmPathInfoStore from context", e);
|
||||||
|
}
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPathFromConfiguration() {
|
||||||
|
logger.debug("using base path from configuration: " + scmConfiguration.getBaseUrl());
|
||||||
|
return scmConfiguration.getBaseUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProtocolWrapper extends HttpScmProtocol {
|
private class ProtocolWrapper extends HttpScmProtocol {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm;
|
||||||
|
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
@@ -8,11 +8,11 @@ import static org.mockito.Mockito.when;
|
|||||||
/**
|
/**
|
||||||
* A mockito implementation of CDI {@link javax.inject.Provider}.
|
* A mockito implementation of CDI {@link javax.inject.Provider}.
|
||||||
*/
|
*/
|
||||||
class MockProvider {
|
public class MockProvider {
|
||||||
|
|
||||||
private MockProvider() {}
|
private MockProvider() {}
|
||||||
|
|
||||||
static <I> Provider<I> of(I instance) {
|
public static <I> Provider<I> of(I instance) {
|
||||||
@SuppressWarnings("unchecked") // Can't make mockito return typed provider
|
@SuppressWarnings("unchecked") // Can't make mockito return typed provider
|
||||||
Provider<I> provider = mock(Provider.class);
|
Provider<I> provider = mock(Provider.class);
|
||||||
when(provider.get()).thenReturn(instance);
|
when(provider.get()).thenReturn(instance);
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import com.google.inject.ProvisionException;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.mockito.stubbing.OngoingStubbing;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
|
import sonia.scm.api.v2.resources.ScmPathInfo;
|
||||||
|
import sonia.scm.api.v2.resources.ScmPathInfoStore;
|
||||||
|
import sonia.scm.config.ScmConfiguration;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.web.filter.PermissionFilter;
|
||||||
|
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.servlet.ServletConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.same;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
public class InitializingHttpScmProtocolWrapperTest {
|
||||||
|
|
||||||
|
private static final Repository REPOSITORY = new Repository("", "git", "space", "name");
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ScmProviderHttpServlet delegateServlet;
|
||||||
|
@Mock
|
||||||
|
private PermissionFilter permissionFilter;
|
||||||
|
@Mock
|
||||||
|
private ScmPathInfoStore pathInfoStore;
|
||||||
|
@Mock
|
||||||
|
private ScmConfiguration scmConfiguration;
|
||||||
|
private Provider<ScmPathInfoStore> pathInfoStoreProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HttpServletRequest request;
|
||||||
|
@Mock
|
||||||
|
private HttpServletResponse response;
|
||||||
|
@Mock
|
||||||
|
private ServletConfig servletConfig;
|
||||||
|
|
||||||
|
private InitializingHttpScmProtocolWrapper wrapper;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
initMocks(this);
|
||||||
|
pathInfoStoreProvider = MockProvider.of(pathInfoStore);
|
||||||
|
wrapper = new InitializingHttpScmProtocolWrapper(MockProvider.of(this.delegateServlet), MockProvider.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) {};
|
||||||
|
when(scmConfiguration.getBaseUrl()).thenReturn("http://example.com/scm");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldUsePathFromPathInfo() {
|
||||||
|
mockSetPathInfo();
|
||||||
|
|
||||||
|
HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY);
|
||||||
|
|
||||||
|
assertEquals("http://example.com/scm/repo/space/name", httpScmProtocol.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldUseConfigurationWhenPathInfoNotSet() {
|
||||||
|
HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY);
|
||||||
|
|
||||||
|
assertEquals("http://example.com/scm/repo/space/name", httpScmProtocol.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldUseConfigurationWhenNotInRequestScope() {
|
||||||
|
when(pathInfoStoreProvider.get()).thenThrow(new ProvisionException("test"));
|
||||||
|
|
||||||
|
HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY);
|
||||||
|
|
||||||
|
assertEquals("http://example.com/scm/repo/space/name", httpScmProtocol.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldInitializeAndDelegateRequestThroughFilter() throws ServletException, IOException {
|
||||||
|
doAnswer(proceedInvocation()).
|
||||||
|
when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any());
|
||||||
|
HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY);
|
||||||
|
|
||||||
|
httpScmProtocol.serve(request, response, servletConfig);
|
||||||
|
|
||||||
|
verify(delegateServlet).init(servletConfig);
|
||||||
|
verify(delegateServlet).service(request, response, REPOSITORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotDelegateRequestWhenFilterBlocks() throws ServletException, IOException {
|
||||||
|
doNothing().
|
||||||
|
when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any());
|
||||||
|
HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY);
|
||||||
|
|
||||||
|
httpScmProtocol.serve(request, response, servletConfig);
|
||||||
|
|
||||||
|
verify(delegateServlet, never()).service(request, response, REPOSITORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldInitializeOnlyOnce() throws ServletException, IOException {
|
||||||
|
doAnswer(proceedInvocation()).
|
||||||
|
when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any());
|
||||||
|
HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY);
|
||||||
|
|
||||||
|
httpScmProtocol.serve(request, response, servletConfig);
|
||||||
|
httpScmProtocol.serve(request, response, servletConfig);
|
||||||
|
|
||||||
|
verify(delegateServlet, times(1)).init(servletConfig);
|
||||||
|
verify(delegateServlet, times(2)).service(request, response, REPOSITORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Answer proceedInvocation() {
|
||||||
|
return invocation -> {
|
||||||
|
((PermissionFilter.ContinuationServlet) invocation.getArgument(3)).doService();
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private OngoingStubbing<ScmPathInfo> mockSetPathInfo() {
|
||||||
|
return when(pathInfoStore.get()).thenReturn(new ScmPathInfo() {
|
||||||
|
@Override
|
||||||
|
public URI getApiRestUri() {
|
||||||
|
return URI.create("http://example.com/scm/api/rest/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -49,6 +49,13 @@
|
|||||||
<artifactId>scm-core</artifactId>
|
<artifactId>scm-core</artifactId>
|
||||||
<version>2.0.0-SNAPSHOT</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>sonia.scm</groupId>
|
||||||
|
<artifactId>scm-core</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>sonia.scm</groupId>
|
<groupId>sonia.scm</groupId>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.repository.Branch;
|
import sonia.scm.repository.Branch;
|
||||||
import sonia.scm.repository.Branches;
|
import sonia.scm.repository.Branches;
|
||||||
import sonia.scm.repository.Changeset;
|
import sonia.scm.repository.Changeset;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.api.rest.AuthorizationExceptionMapper;
|
import sonia.scm.api.rest.AuthorizationExceptionMapper;
|
||||||
import sonia.scm.repository.Changeset;
|
import sonia.scm.repository.Changeset;
|
||||||
import sonia.scm.repository.ChangesetPagingResult;
|
import sonia.scm.repository.ChangesetPagingResult;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.PageResult;
|
import sonia.scm.PageResult;
|
||||||
import sonia.scm.api.rest.JSONContextResolver;
|
import sonia.scm.api.rest.JSONContextResolver;
|
||||||
import sonia.scm.api.rest.ObjectMapperProvider;
|
import sonia.scm.api.rest.ObjectMapperProvider;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.DynamicTest;
|
|||||||
import org.junit.jupiter.api.TestFactory;
|
import org.junit.jupiter.api.TestFactory;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
import sonia.scm.repository.Permission;
|
import sonia.scm.repository.Permission;
|
||||||
import sonia.scm.repository.PermissionType;
|
import sonia.scm.repository.PermissionType;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.PageResult;
|
import sonia.scm.PageResult;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
import sonia.scm.repository.Permission;
|
import sonia.scm.repository.Permission;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.repository.RepositoryManager;
|
import sonia.scm.repository.RepositoryManager;
|
||||||
import sonia.scm.repository.RepositoryType;
|
import sonia.scm.repository.RepositoryType;
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
@@ -22,8 +23,10 @@ import java.util.List;
|
|||||||
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
import static org.junit.Assert.*;
|
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import org.jboss.resteasy.core.Dispatcher;
|
import org.jboss.resteasy.core.Dispatcher;
|
||||||
import org.jboss.resteasy.mock.MockDispatcherFactory;
|
|
||||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -10,6 +9,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.repository.BrowserResult;
|
import sonia.scm.repository.BrowserResult;
|
||||||
import sonia.scm.repository.FileObject;
|
import sonia.scm.repository.FileObject;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.api.rest.AuthorizationExceptionMapper;
|
import sonia.scm.api.rest.AuthorizationExceptionMapper;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import sonia.scm.MockProvider;
|
||||||
import sonia.scm.PageResult;
|
import sonia.scm.PageResult;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserManager;
|
import sonia.scm.user.UserManager;
|
||||||
|
|||||||
Reference in New Issue
Block a user