import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonarqube.ws.MediaTypes;
import org.sonar.server.qualityprofile.QProfileBackuper;
import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonarqube.ws.MediaTypes;
public class BackupAction implements QProfileWsAction {
public void handle(Request request, Response response) throws Exception {
Stream stream = response.stream();
stream.setMediaType(MediaTypes.XML);
- OutputStreamWriter writer = new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8);
DbSession dbSession = dbClient.openSession(false);
+ OutputStreamWriter writer = new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8);
try {
String profileKey = QProfileIdentificationParamUtils.getProfileKeyFromParameters(request, profileFactory, dbSession);
- backuper.backup(profileKey, writer);
response.setHeader("Content-Disposition", String.format("attachment; filename=%s.xml", profileKey));
+ backuper.backup(profileKey, writer);
} finally {
dbSession.close();
IOUtils.closeQuietly(writer);
return localRequest.hasParam(key);
}
+ @Override
+ public String getPath() {
+ return localRequest.getPath();
+ }
+
@Override
public String method() {
return localRequest.getMethod();
String formatSuffix = substringAfterLast(url, ".");
return SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX.get(formatSuffix.toLowerCase(Locale.ENGLISH));
}
+
+ @Override
+ public String getPath(){
+ return source.getRequestURI().replaceFirst(source.getContextPath(), "");
+ }
}
*/
package org.sonar.server.ws;
-import java.io.ByteArrayOutputStream;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.sonarqube.ws.MediaTypes.JSON;
+import static org.sonarqube.ws.MediaTypes.XML;
+
+import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
+import javax.servlet.http.HttpServletResponse;
import org.sonar.api.server.ws.Response;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.utils.text.XmlWriter;
-import org.sonarqube.ws.MediaTypes;
public class ServletResponse implements Response {
- private Map<String, String> headers = new HashMap<>();
+ private final ServletStream stream;
- public static class ServletStream implements Stream {
- private String mediaType;
- private int httpStatus = 200;
- private final ByteArrayOutputStream output = new ByteArrayOutputStream();
+ public ServletResponse(HttpServletResponse response) {
+ stream = new ServletStream(response);
+ }
- @CheckForNull
- public String mediaType() {
- return mediaType;
- }
+ public static class ServletStream implements Stream {
+ private final HttpServletResponse response;
- public int httpStatus() {
- return httpStatus;
+ public ServletStream(HttpServletResponse response) {
+ this.response = response;
+ this.response.setStatus(200);
+ // SONAR-6964 WS should not be cached by browser
+ this.response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
}
@Override
public ServletStream setMediaType(String s) {
- this.mediaType = s;
+ this.response.setContentType(s);
return this;
}
@Override
public ServletStream setStatus(int httpStatus) {
- this.httpStatus = httpStatus;
+ this.response.setStatus(httpStatus);
return this;
}
@Override
public OutputStream output() {
- return output;
+ try {
+ return response.getOutputStream();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
}
- public String outputAsString() {
- return new String(output.toByteArray(), StandardCharsets.UTF_8);
+ HttpServletResponse response() {
+ return response;
}
public ServletStream reset() {
- output.reset();
+ response.reset();
return this;
}
}
- private final ServletStream stream = new ServletStream();
-
@Override
public JsonWriter newJsonWriter() {
- stream.setMediaType(MediaTypes.JSON);
- return JsonWriter.of(new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8));
+ stream.setMediaType(JSON);
+ return JsonWriter.of(new OutputStreamWriter(stream.output(), UTF_8));
}
@Override
public XmlWriter newXmlWriter() {
- stream.setMediaType(MediaTypes.XML);
- return XmlWriter.of(new OutputStreamWriter(stream.output(), StandardCharsets.UTF_8));
+ stream.setMediaType(XML);
+ return XmlWriter.of(new OutputStreamWriter(stream.output(), UTF_8));
}
@Override
@Override
public Response setHeader(String name, String value) {
- headers.put(name, value);
+ stream.response().setHeader(name, value);
return this;
}
@Override
public Collection<String> getHeaderNames() {
- return headers.keySet();
+ return stream.response().getHeaderNames();
}
@Override
public String getHeader(String name) {
- return headers.get(name);
+ return stream.response().getHeader(name);
}
}
*/
package org.sonar.server.ws;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.lang.String.format;
+import static org.apache.commons.lang.StringUtils.substring;
+import static org.apache.commons.lang.StringUtils.substringAfterLast;
+import static org.apache.commons.lang.StringUtils.substringBeforeLast;
+import static org.sonar.server.ws.RequestVerifier.verifyRequest;
+import static org.sonar.server.ws.ServletRequest.SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX;
+
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.i18n.I18n;
import org.sonar.api.server.ServerSide;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.MediaTypes;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static java.lang.String.format;
-import static org.apache.commons.lang.StringUtils.substringAfterLast;
-import static org.sonar.server.ws.RequestVerifier.verifyRequest;
-import static org.sonar.server.ws.ServletRequest.SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX;
-
/**
* @since 4.2
*/
// nothing
}
- /**
- * Used by Ruby on Rails to add ws routes. See WEB_INF/lib/java_ws_routing.rb
- */
- public List<WebService.Controller> controllers() {
+ List<WebService.Controller> controllers() {
return context.controllers();
}
@Override
public LocalResponse call(LocalRequest request) {
- String controller = StringUtils.substringBeforeLast(request.getPath(), "/");
- String action = substringAfterLast(request.getPath(), "/");
DefaultLocalResponse localResponse = new DefaultLocalResponse();
- execute(new LocalRequestAdapter(request), localResponse, controller, action, null);
+ execute(new LocalRequestAdapter(request), localResponse);
return localResponse;
}
- public void execute(Request request, Response response, String controllerPath, String actionKey, @Nullable String actionExtension) {
+ public void execute(Request request, Response response) {
try {
- WebService.Action action = getAction(controllerPath, actionKey);
+ ActionExtractor actionExtractor = new ActionExtractor(request.getPath());
+ WebService.Action action = getAction(actionExtractor.getController(), actionExtractor.getAction());
if (request instanceof ValidatingRequest) {
((ValidatingRequest) request).setAction(action);
((ValidatingRequest) request).setLocalConnector(this);
}
- checkActionExtension(actionExtension);
+ checkActionExtension(actionExtractor.getExtension());
verifyRequest(action, request);
action.handler().handle(request, response);
} catch (IllegalArgumentException e) {
checkArgument(SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX.get(actionExtension.toLowerCase(Locale.ENGLISH)) != null, "Unknown action extension: %s", actionExtension);
}
+ private static class ActionExtractor {
+ private static final String SLASH = "/";
+ private static final String POINT = ".";
+
+ private final String controller;
+ private final String action;
+ private final String extension;
+
+ ActionExtractor(String path) {
+ String pathWithoutExtension = substringBeforeLast(path, POINT);
+ this.controller = extractController(pathWithoutExtension);
+ this.action = substringAfterLast(pathWithoutExtension, SLASH);
+ checkArgument(!action.isEmpty(), "Url is incorrect : '%s'", path);
+ this.extension = substringAfterLast(path, POINT);
+ }
+
+ private static String extractController(String path) {
+ String controller = substringBeforeLast(path, SLASH);
+ if (controller.startsWith(SLASH)) {
+ return substring(controller, 1);
+ }
+ return controller;
+ }
+
+ String getController() {
+ return controller;
+ }
+
+ String getAction() {
+ return action;
+ }
+
+ @CheckForNull
+ String getExtension() {
+ return extension;
+ }
+ }
+
}
package org.sonar.server.ws;
-import static java.lang.String.format;
-
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
import org.sonar.api.server.ws.RailsHandler;
import org.sonar.api.web.ServletFilter;
public class WebServiceFilter extends ServletFilter {
private final WebServiceEngine webServiceEngine;
- private final Map<String, WsUrl> wsUrls = new HashMap<>();
private final List<String> includeUrls = new ArrayList<>();
+ private final List<String> excludeUrls = new ArrayList<>();
public WebServiceFilter(WebServiceEngine webServiceEngine) {
this.webServiceEngine = webServiceEngine;
webServiceEngine.controllers().stream()
.forEach(controller -> controller.actions().stream()
- .filter(action -> !(action.handler() instanceof RailsHandler) && !(action.handler() instanceof ServletFilterHandler))
.forEach(action -> {
- String url = "/" + action.path();
- wsUrls.put(url, new WsUrl(controller.path(), action.key()));
- includeUrls.add(url + "*");
+ // Rails and servlet filter WS should not be executed by the web service engine
+ if (!(action.handler() instanceof RailsHandler) && !(action.handler() instanceof ServletFilterHandler)) {
+ includeUrls.add("/" + controller.path() + "/*");
+ } else {
+ excludeUrls.add("/" + action.path() + "*");
+ }
}));
}
public UrlPattern doGetPattern() {
return UrlPattern.builder()
.includes(includeUrls)
+ .excludes(excludeUrls)
.build();
}
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(), "");
-
- String[] pathWithExtension = getPathWithExtension(path);
- WsUrl url = wsUrls.get(pathWithExtension[0]);
- if (url == null) {
- throw new IllegalStateException(format("Unknown path : %s", path));
- }
ServletRequest wsRequest = new ServletRequest(request);
- ServletResponse wsResponse = new ServletResponse();
- webServiceEngine.execute(wsRequest, wsResponse, url.getController(), url.getAction(), pathWithExtension[1]);
- writeResponse(wsResponse, response);
- }
-
- private static void writeResponse(ServletResponse wsResponse, HttpServletResponse response) throws IOException {
- // SONAR-6964 WS should not be cached by browser
- response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
- for (String header : wsResponse.getHeaderNames()) {
- response.setHeader(header, wsResponse.getHeader(header));
- }
-
- response.setContentType(wsResponse.stream().mediaType());
- response.setStatus(wsResponse.stream().httpStatus());
-
- OutputStream responseOutput = response.getOutputStream();
- ByteArrayOutputStream wsOutputStream = (ByteArrayOutputStream) wsResponse.stream().output();
- IOUtils.write(wsOutputStream.toByteArray(), responseOutput);
- responseOutput.flush();
- responseOutput.close();
- }
-
- private static String[] getPathWithExtension(String fullPath) {
- String path = fullPath;
- String extension = null;
- int semiColonPos = fullPath.lastIndexOf('.');
- if (semiColonPos > 0) {
- path = fullPath.substring(0, semiColonPos);
- extension = fullPath.substring(semiColonPos + 1);
- }
- return new String[] {path, extension};
+ ServletResponse wsResponse = new ServletResponse(response);
+ webServiceEngine.execute(wsRequest, wsResponse);
}
@Override
this.status = i;
return this;
}
+
@Override
public OutputStream output() {
return output;
}
+ public String outputAsString() {
+ return new String(output.toByteArray(), StandardCharsets.UTF_8);
+ }
}
@Override
return this;
}
- @Override
public Collection<String> getHeaderNames() {
return headers.keySet();
}
- @Override
- public String getHeader(String name) {
+ public String getHeader(String name){
return headers.get(name);
}
request.readInputStreamParam("param1");
}
+ @Test
+ public void getPath() throws Exception {
+ when(source.getRequestURI()).thenReturn("/sonar/path/to/resource/search");
+ when(source.getContextPath()).thenReturn("/sonar");
+
+ ServletRequest request = new ServletRequest(source);
+
+ assertThat(request.getPath()).isEqualTo("/path/to/resource/search");
+ }
+
@Test
public void to_string() {
when(source.getRequestURL()).thenReturn(new StringBuffer("http:localhost:9000/api/issues"));
--- /dev/null
+/*
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.sonarqube.ws.MediaTypes.JSON;
+import static org.sonarqube.ws.MediaTypes.XML;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class ServletResponseTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ ServletOutputStream output = mock(ServletOutputStream.class);
+
+ HttpServletResponse response = mock(HttpServletResponse.class);
+
+ ServletResponse underTest = new ServletResponse(response);
+
+ @Before
+ public void setUp() throws Exception {
+ when(response.getOutputStream()).thenReturn(output);
+ }
+
+ @Test
+ public void test_default_header() throws Exception {
+ verify(response).setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ }
+
+ @Test
+ public void set_header() throws Exception {
+ underTest.setHeader("header", "value");
+
+ verify(response).setHeader("header", "value");
+ }
+
+ @Test
+ public void get_header() throws Exception {
+ underTest.getHeader("header");
+
+ verify(response).getHeader("header");
+ }
+
+ @Test
+ public void get_header_names() throws Exception {
+ underTest.getHeaderNames();
+
+ verify(response).getHeaderNames();
+ }
+
+ @Test
+ public void test_default_status() throws Exception {
+ verify(response).setStatus(200);
+ }
+
+ @Test
+ public void set_status() throws Exception {
+ underTest.stream().setStatus(404);
+
+ verify(response).setStatus(404);
+ }
+
+ @Test
+ public void test_output() throws Exception {
+ assertThat(underTest.stream().output()).isEqualTo(output);
+ }
+
+
+ @Test
+ public void test_reset() throws Exception {
+ underTest.stream().reset();
+
+ verify(response).reset();
+ }
+
+ @Test
+ public void test_newJsonWriter() throws Exception {
+ underTest.newJsonWriter();
+
+ verify(response).setContentType(JSON);
+ verify(response).getOutputStream();
+ }
+
+ @Test
+ public void test_newXmlWriter() throws Exception {
+ underTest.newXmlWriter();
+
+ verify(response).setContentType(XML);
+ verify(response).getOutputStream();
+ }
+
+ @Test
+ public void test_noContent() throws Exception {
+ underTest.noContent();
+
+ verify(response).setStatus(204);
+ verify(response, never()).getOutputStream();
+ }
+}
*/
package org.sonar.server.ws;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.base.Throwables;
import java.io.InputStream;
import java.util.HashMap;
import org.apache.commons.io.IOUtils;
import org.sonar.api.server.ws.internal.ValidatingRequest;
-import static com.google.common.base.Preconditions.checkNotNull;
-
public class TestRequest extends ValidatingRequest {
private final Map<String, String> params = new HashMap<>();
private String method = "GET";
private String mimeType = "application/octet-stream";
+ private String path;
@Override
protected String readParam(String key) {
return params.containsKey(key);
}
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ public TestRequest setPath(String path) {
+ this.path = path;
+ return this;
+ }
+
public TestRequest setMethod(String method) {
checkNotNull(method);
this.method = method;
*/
package org.sonar.server.ws;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import com.google.common.collect.Maps;
import java.io.IOException;
import java.io.InputStream;
import org.sonar.server.tester.UserSessionRule;
import org.sonarqube.ws.MediaTypes;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class WebServiceEngineTest {
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
+
I18n i18n = mock(I18n.class);
WebServiceEngine underTest = new WebServiceEngine(new WebService[] {new SystemWs()}, i18n, userSessionRule);
@Test
public void execute_request() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "health", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/health");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
+
+ assertThat(response.stream().outputAsString()).isEqualTo("good");
+ }
+
+ @Test
+ public void execute_request_when_path_does_not_begin_with_slash() {
+ ValidatingRequest request = new SimpleRequest("GET", "api/system/health");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("good");
}
@Test
public void execute_request_with_action_suffix() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "health", "PROTOBUF");
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/health");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("good");
}
@Test
public void bad_request_if_action_suffix_is_not_supported() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "health", "bat");
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/health.bat");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
- assertThat(response.stream().httpStatus()).isEqualTo(400);
+ assertThat(response.stream().status()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown action extension: bat\"}]}");
}
@Test
public void no_content() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "alive", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/alive");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEmpty();
}
@Test
public void bad_controller() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/xxx", "health", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/xxx/health");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown web service: api/xxx\"}]}");
}
@Test
public void bad_action() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "xxx", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/xxx");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown action: api/system/xxx\"}]}");
}
@Test
public void method_get_not_allowed() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "ping", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/ping");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method POST is required\"}]}");
}
@Test
public void method_post_required() {
- ValidatingRequest request = new SimpleRequest("POST");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "ping", null);
+ ValidatingRequest request = new SimpleRequest("POST", "/api/system/ping");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("pong");
}
@Test
public void unknown_parameter_is_set() {
- ValidatingRequest request = new SimpleRequest("GET").setParam("unknown", "Unknown");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "fail_with_undeclared_parameter", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/fail_with_undeclared_parameter").setParam("unknown", "Unknown");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"BUG - parameter 'unknown' is undefined for action 'fail_with_undeclared_parameter'\"}]}");
}
@Test
public void required_parameter_is_not_set() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "print", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/print");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"The 'message' parameter is missing\"}]}");
}
@Test
public void optional_parameter_is_not_set() {
- ValidatingRequest request = new SimpleRequest("GET").setParam("message", "Hello World");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "print", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/print").setParam("message", "Hello World");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("Hello World by -");
}
@Test
public void optional_parameter_is_set() {
- ValidatingRequest request = new SimpleRequest("GET")
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/print")
.setParam("message", "Hello World")
.setParam("author", "Marcel");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "print", null);
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("Hello World by Marcel");
}
@Test
public void param_value_is_in_possible_values() {
- ValidatingRequest request = new SimpleRequest("GET")
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/print")
.setParam("message", "Hello World")
.setParam("format", "json");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "print", null);
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("Hello World by -");
}
@Test
public void param_value_is_not_in_possible_values() {
- ValidatingRequest request = new SimpleRequest("GET")
+ ValidatingRequest request = new SimpleRequest("GET", "api/system/print")
.setParam("message", "Hello World")
.setParam("format", "html");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "print", null);
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Value of parameter 'format' (html) must be one of: [json, xml]\"}]}");
}
@Test
public void internal_error() {
- ValidatingRequest request = new SimpleRequest("GET");
- ServletResponse response = new ServletResponse();
- underTest.execute(request, response, "api/system", "fail", null);
+ ValidatingRequest request = new SimpleRequest("GET", "/api/system/fail");
+ DumbResponse response = new DumbResponse();
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unexpected\"}]}");
- assertThat(response.stream().httpStatus()).isEqualTo(500);
+ assertThat(response.stream().status()).isEqualTo(500);
assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON);
}
@Test
public void bad_request_with_i18n_message() {
userSessionRule.setLocale(Locale.ENGLISH);
- ValidatingRequest request = new SimpleRequest("GET").setParam("count", "3");
- ServletResponse response = new ServletResponse();
+ ValidatingRequest request = new SimpleRequest("GET", "api/system/fail_with_i18n_message").setParam("count", "3");
+ DumbResponse response = new DumbResponse();
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("reason #0");
- underTest.execute(request, response, "api/system", "fail_with_i18n_message", null);
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo(
"{\"errors\":[{\"msg\":\"reason #0\"}]}");
- assertThat(response.stream().httpStatus()).isEqualTo(400);
+ assertThat(response.stream().status()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON);
}
@Test
public void bad_request_with_multiple_messages() {
- ValidatingRequest request = new SimpleRequest("GET").setParam("count", "3");
- ServletResponse response = new ServletResponse();
+ ValidatingRequest request = new SimpleRequest("GET", "api/system/fail_with_multiple_messages").setParam("count", "3");
+ DumbResponse response = new DumbResponse();
- underTest.execute(request, response, "api/system", "fail_with_multiple_messages", null);
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ "{\"msg\":\"Bad request reason #0\"},"
+ "{\"msg\":\"Bad request reason #1\"},"
+ "{\"msg\":\"Bad request reason #2\"}"
+ "]}");
- assertThat(response.stream().httpStatus()).isEqualTo(400);
+ assertThat(response.stream().status()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON);
}
public void bad_request_with_multiple_i18n_messages() {
userSessionRule.setLocale(Locale.ENGLISH);
- ValidatingRequest request = new SimpleRequest("GET").setParam("count", "3");
- ServletResponse response = new ServletResponse();
+ ValidatingRequest request = new SimpleRequest("GET", "api/system/fail_with_multiple_i18n_messages").setParam("count", "3");
+ DumbResponse response = new DumbResponse();
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("reason #0");
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 1)).thenReturn("reason #1");
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 2)).thenReturn("reason #2");
- underTest.execute(request, response, "api/system", "fail_with_multiple_i18n_messages", null);
+ underTest.execute(request, response);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[" +
"{\"msg\":\"reason #0\"}," +
"{\"msg\":\"reason #1\"}," +
"{\"msg\":\"reason #2\"}]}");
- assertThat(response.stream().httpStatus()).isEqualTo(400);
+ assertThat(response.stream().status()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON);
}
@Test
public void should_handle_headers() {
- ServletResponse response = new ServletResponse();
+ DumbResponse response = new DumbResponse();
String name = "Content-Disposition";
String value = "attachment; filename=sonarqube.zip";
response.setHeader(name, value);
private static class SimpleRequest extends ValidatingRequest {
private final String method;
+ private String path;
private Map<String, String> params = Maps.newHashMap();
- private SimpleRequest(String method) {
+ private SimpleRequest(String method, String path) {
this.method = method;
+ this.path = path;
}
@Override
return params.keySet().contains(key);
}
+ @Override
+ public String getPath() {
+ return path;
+ }
+
@Override
protected String readParam(String key) {
return params.get(key);
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.sonar.server.ws.WebServiceFilterTest.WsUrl.newWsUrl;
newWsUrl("api/issues", "search"),
newWsUrl("batch", "index"),
newWsUrl("api/authentication", "login").setHandler(ServletFilterHandler.INSTANCE),
- newWsUrl("api/resources", "index").setHandler(RailsHandler.INSTANCE));
+ newWsUrl("api/resources", "index").setHandler(RailsHandler.INSTANCE),
+ newWsUrl("api/issues", "deprecatedSearch").setHandler(RailsHandler.INSTANCE));
assertThat(underTest.doGetPattern().matches("/api/issues/search")).isTrue();
assertThat(underTest.doGetPattern().matches("/api/issues/search.protobuf")).isTrue();
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("/foo")).isFalse();
}
@Test
- public void execute() throws Exception {
- initWebServiceEngine(newWsUrl("api/issues", "search"));
- when(request.getRequestURI()).thenReturn("/api/issues/search");
-
- underTest.doFilter(request, response, chain);
-
- verify(webServiceEngine).execute(any(ServletRequest.class), any(org.sonar.server.ws.ServletResponse.class), eq("api/issues"), eq("search"), eq(null));
-
- verify(response).setStatus(200);
- verify(response).setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
-
- verify(responseOutput).flush();
- verify(responseOutput).close();
- verifyZeroInteractions(chain);
- }
-
- @Test
- public void execute_with_extension() throws Exception {
- initWebServiceEngine(newWsUrl("api/issues", "search"));
- when(request.getRequestURI()).thenReturn("/api/issues/search.protobuff");
+ public void execute_ws() throws Exception {
+ underTest = new WebServiceFilter(webServiceEngine);
underTest.doFilter(request, response, chain);
- verify(webServiceEngine).execute(any(ServletRequest.class), any(org.sonar.server.ws.ServletResponse.class), eq("api/issues"), eq("search"), eq("protobuff"));
- }
-
- @Test
- public void fail_on_unknown_path() throws Exception {
- initWebServiceEngine(newWsUrl("api/issues", "search"));
- when(request.getRequestURI()).thenReturn("/api/resources/index");
-
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Unknown path : /api/resources/index");
- underTest.doFilter(request, response, chain);
+ verify(webServiceEngine).execute(any(ServletRequest.class), any(org.sonar.server.ws.ServletResponse.class));
}
private void initWebServiceEngine(WsUrl... wsUrls) {
*/
package org.sonar.server.ws;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.ws.RequestVerifier.verifyRequest;
+
import com.google.common.collect.Maps;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import org.sonar.test.JsonAssert;
import org.sonarqube.ws.MediaTypes;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.server.ws.RequestVerifier.verifyRequest;
-
/**
* @since 4.2
*/
public static class TestRequest extends ValidatingRequest {
private final String method;
+ private String path;
private Map<String, String> params = Maps.newHashMap();
return params.keySet().contains(key);
}
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ public TestRequest setPath(String path) {
+ this.path = path;
+ return this;
+ }
+
public TestRequest setParams(Map<String, String> m) {
this.params = m;
return this;
*/
@Beta
public abstract LocalConnector localConnector();
+
+ /**
+ * Return path of the request
+ * @since 6.0
+ */
+ public abstract String getPath();
}
*/
package org.sonar.api.server.ws.internal;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.collect.Maps;
import java.io.InputStream;
import java.util.Map;
import org.sonar.api.server.ws.LocalConnector;
import org.sonar.api.server.ws.Request;
-import static com.google.common.base.Preconditions.checkNotNull;
-
/**
* Fake implementation of {@link org.sonar.api.server.ws.Request} used
* for testing. Call the method {@link #setParam(String, String)} to
private final Map<String, String> params = Maps.newHashMap();
private String mediaType = "application/json";
+ private String path;
@Override
public String method() {
public LocalConnector localConnector() {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ public SimpleGetRequest setPath(String path) {
+ this.path = path;
+ return this;
+ }
}
*/
package org.sonar.api.server.ws;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
import com.google.common.collect.Maps;
import java.io.InputStream;
import java.util.Map;
import org.sonar.api.server.ws.internal.ValidatingRequest;
import org.sonar.api.utils.DateUtils;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
public class RequestTest {
@Rule
return params.keySet().contains(key);
}
+ @Override
+ public String getPath() {
+ return null;
+ }
+
public FakeRequest setParam(String key, @Nullable String value) {
if (value != null) {
params.put(key, value);