From 3a602ff62b1a6a44ba29e647b8c943b569c13c32 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Fri, 6 Jan 2017 13:48:51 +0100 Subject: [PATCH] SONAR-7300 Redirect api/properties to api/properties/index --- .../sonar/server/config/ws/IndexAction.java | 2 +- .../platformlevel/PlatformLevel4.java | 2 + .../ws/DeprecatedRestWebServiceFilter.java | 120 ++++++++++++++++++ .../DeprecatedRestWebServiceFilterTest.java | 103 +++++++++++++++ .../sonar/server/ws/WebServiceFilterTest.java | 15 ++- 5 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedRestWebServiceFilter.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedRestWebServiceFilterTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java b/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java index fef3bad5035..67bce460b1d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java @@ -63,7 +63,7 @@ public class IndexAction implements WsAction { private static final Splitter COMMA_SPLITTER = Splitter.on(","); private static final String COMMA_ENCODED_VALUE = "%2C"; - private static final String PARAM_KEY = "key"; + public static final String PARAM_KEY = "key"; private static final String PARAM_COMPONENT = "resource"; private final DbClient dbClient; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 311dba084f7..6fe456ddf41 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -210,6 +210,7 @@ import org.sonar.server.view.index.ViewIndex; import org.sonar.server.view.index.ViewIndexDefinition; import org.sonar.server.view.index.ViewIndexer; import org.sonar.server.webhook.ws.WebhooksWsModule; +import org.sonar.server.ws.DeprecatedRestWebServiceFilter; import org.sonar.server.ws.WebServiceEngine; import org.sonar.server.ws.WebServiceFilter; import org.sonar.server.ws.WebServicesWs; @@ -323,6 +324,7 @@ public class PlatformLevel4 extends PlatformLevel { WebServiceEngine.class, WebServicesWs.class, WebServiceFilter.class, + DeprecatedRestWebServiceFilter.class, // localization L10nWs.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedRestWebServiceFilter.java b/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedRestWebServiceFilter.java new file mode 100644 index 00000000000..2ffd0e5fd73 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ws/DeprecatedRestWebServiceFilter.java @@ -0,0 +1,120 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.ws; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.sonar.api.web.ServletFilter; +import org.sonar.server.config.ws.IndexAction; + +import static org.sonar.server.config.ws.PropertiesWs.CONTROLLER_PROPERTIES; + +/** + * This filter is used to execute some deprecated Java WS, that were using REST + */ +public class DeprecatedRestWebServiceFilter extends ServletFilter { + + private final WebServiceEngine webServiceEngine; + + public DeprecatedRestWebServiceFilter(WebServiceEngine webServiceEngine) { + this.webServiceEngine = webServiceEngine; + } + + @Override + public UrlPattern doGetPattern() { + return UrlPattern.builder() + .includes("/" + CONTROLLER_PROPERTIES + "/*") + .build(); + } + + @Override + public void doFilter(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + String path = request.getRequestURI().replaceFirst(request.getContextPath(), ""); + Map additionalParams = new HashMap<>(); + Optional key = getKey(path); + key.ifPresent(s -> additionalParams.put(IndexAction.PARAM_KEY, s)); + ServletRequest wsRequest = new ServletRequest(request, CONTROLLER_PROPERTIES + "/index", additionalParams); + ServletResponse wsResponse = new ServletResponse(response); + webServiceEngine.execute(wsRequest, wsResponse); + } + + private static Optional getKey(String path) { + if (path.equals("/" + CONTROLLER_PROPERTIES)) { + return Optional.empty(); + } + String key = path.replace("/" + CONTROLLER_PROPERTIES + "/", ""); + if (key.isEmpty()) { + return Optional.empty(); + } + return Optional.of(key); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // Nothing to do + } + + @Override + public void destroy() { + // Nothing to do + } + + static class ServletRequest extends org.sonar.server.ws.ServletRequest { + + private final String path; + private final Map additionalParams; + + public ServletRequest(HttpServletRequest source, String path, Map additionalParams) { + super(source); + this.path = path; + this.additionalParams = additionalParams; + } + + @Override + public String getPath() { + return path; + } + + @Override + public boolean hasParam(String key) { + return additionalParams.containsKey(key) || super.hasParam(key); + } + + @Override + protected String readParam(String key) { + String param = additionalParams.get(key); + if (param != null) { + return param; + } + return super.readParam(key); + } + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedRestWebServiceFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedRestWebServiceFilterTest.java new file mode 100644 index 00000000000..f845e0d6581 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/ws/DeprecatedRestWebServiceFilterTest.java @@ -0,0 +1,103 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.ws; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.ArgumentCaptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class DeprecatedRestWebServiceFilterTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private WebServiceEngine webServiceEngine = mock(WebServiceEngine.class); + + private HttpServletRequest request = mock(HttpServletRequest.class); + private HttpServletResponse response = mock(HttpServletResponse.class); + private FilterChain chain = mock(FilterChain.class); + private ArgumentCaptor servletRequestCaptor = ArgumentCaptor.forClass(ServletRequest.class); + + private DeprecatedRestWebServiceFilter underTest = new DeprecatedRestWebServiceFilter(webServiceEngine); + + @Before + public void setUp() throws Exception { + when(request.getContextPath()).thenReturn("/sonarqube"); + } + + @Test + public void do_get_pattern() throws Exception { + assertThat(underTest.doGetPattern().matches("/api/properties")).isTrue(); + assertThat(underTest.doGetPattern().matches("/api/properties/")).isTrue(); + assertThat(underTest.doGetPattern().matches("/api/properties/my.property")).isTrue(); + assertThat(underTest.doGetPattern().matches("/api/properties/my_property")).isTrue(); + + assertThat(underTest.doGetPattern().matches("/api/issues/search")).isFalse(); + assertThat(underTest.doGetPattern().matches("/batch/index")).isFalse(); + assertThat(underTest.doGetPattern().matches("/foo")).isFalse(); + } + + @Test + public void redirect_api_properties_to_api_properties_index() throws Exception { + when(request.getRequestURI()).thenReturn("/api/properties"); + + underTest.doFilter(request, response, chain); + + verify(webServiceEngine).execute(servletRequestCaptor.capture(), any(ServletResponse.class)); + assertThat(servletRequestCaptor.getValue().getPath()).isEqualTo("api/properties/index"); + assertThat(servletRequestCaptor.getValue().hasParam("key")).isFalse(); + } + + @Test + public void redirect_api_properties_to_api_properties_index_when_no_property() throws Exception { + when(request.getRequestURI()).thenReturn("/api/properties/"); + + underTest.doFilter(request, response, chain); + + verify(webServiceEngine).execute(servletRequestCaptor.capture(), any(ServletResponse.class)); + assertThat(servletRequestCaptor.getValue().getPath()).isEqualTo("api/properties/index"); + assertThat(servletRequestCaptor.getValue().hasParam("key")).isFalse(); + } + + @Test + public void redirect_api_properties_with_property_key() throws Exception { + when(request.getRequestURI()).thenReturn("/api/properties/my.property"); + + underTest.doFilter(request, response, chain); + + verify(webServiceEngine).execute(servletRequestCaptor.capture(), any(ServletResponse.class)); + assertThat(servletRequestCaptor.getValue().getPath()).isEqualTo("api/properties/index"); + assertThat(servletRequestCaptor.getValue().hasParam("key")).isTrue(); + assertThat(servletRequestCaptor.getValue().readParam("key")).isEqualTo("my.property"); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceFilterTest.java index 8e652c4c40f..0871dad3cbc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceFilterTest.java @@ -20,13 +20,6 @@ package org.sonar.server.ws; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.server.ws.WebServiceFilterTest.WsUrl.newWsUrl; - import java.util.ArrayList; import java.util.List; import javax.servlet.FilterChain; @@ -43,6 +36,13 @@ import org.sonar.api.server.ws.RequestHandler; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.sonar.server.ws.WebServiceFilterTest.WsUrl.newWsUrl; + public class WebServiceFilterTest { @Rule @@ -79,6 +79,7 @@ public class WebServiceFilterTest { assertThat(underTest.doGetPattern().matches("/api/resources/index")).isFalse(); assertThat(underTest.doGetPattern().matches("/api/authentication/login")).isFalse(); assertThat(underTest.doGetPattern().matches("/api/issues/deprecatedSearch")).isFalse(); + assertThat(underTest.doGetPattern().matches("/api/properties")).isFalse(); assertThat(underTest.doGetPattern().matches("/foo")).isFalse(); } -- 2.39.5