import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.Locale;
+import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.i18n.I18n;
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
@Override
public LocalResponse call(LocalRequest request) {
String controller = StringUtils.substringBeforeLast(request.getPath(), "/");
- String action = StringUtils.substringAfterLast(request.getPath(), "/");
+ String action = substringAfterLast(request.getPath(), "/");
DefaultLocalResponse localResponse = new DefaultLocalResponse();
- execute(new LocalRequestAdapter(request), localResponse, controller, action);
+ execute(new LocalRequestAdapter(request), localResponse, controller, action, null);
return localResponse;
}
- public void execute(Request request, Response response, String controllerPath, String actionKey) {
+ public void execute(Request request, Response response, String controllerPath, String actionKey, @Nullable String actionExtension) {
try {
WebService.Action action = getAction(controllerPath, actionKey);
if (request instanceof ValidatingRequest) {
((ValidatingRequest) request).setAction(action);
((ValidatingRequest) request).setLocalConnector(this);
}
+ checkActionExtension(actionExtension);
verifyRequest(action, request);
action.handler().handle(request, response);
} catch (IllegalArgumentException e) {
}
private WebService.Action getAction(String controllerPath, String actionKey) {
- String actionKeyWithoutFormatSuffix = actionKey.contains(".") ?
- actionKey.substring(0, actionKey.lastIndexOf('.'))
- : actionKey;
WebService.Controller controller = context.controller(controllerPath);
if (controller == null) {
throw new BadRequestException(format("Unknown web service: %s", controllerPath));
}
- WebService.Action action = controller.action(actionKeyWithoutFormatSuffix);
+ WebService.Action action = controller.action(actionKey);
if (action == null) {
- throw new BadRequestException(format("Unknown action: %s/%s", controllerPath, actionKeyWithoutFormatSuffix));
+ throw new BadRequestException(format("Unknown action: %s/%s", controllerPath, actionKey));
}
return action;
}
json.close();
}
}
+
+ private static void checkActionExtension(@Nullable String actionExtension) {
+ if (isNullOrEmpty(actionExtension)) {
+ return;
+ }
+ checkArgument(SUPPORTED_MEDIA_TYPES_BY_URL_SUFFIX.get(actionExtension.toLowerCase(Locale.ENGLISH)) != null, "Unknown action extension: %s", actionExtension);
+ }
+
}
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
I18n i18n = mock(I18n.class);
- WebServiceEngine engine = new WebServiceEngine(new WebService[] {new SystemWs()}, i18n, userSessionRule);
+
+ WebServiceEngine underTest = new WebServiceEngine(new WebService[] {new SystemWs()}, i18n, userSessionRule);
@Before
public void start() {
- engine.start();
+ underTest.start();
}
@After
public void stop() {
- engine.stop();
+ underTest.stop();
}
@Test
public void load_ws_definitions_at_startup() {
- assertThat(engine.controllers()).hasSize(1);
- assertThat(engine.controllers().get(0).path()).isEqualTo("api/system");
+ assertThat(underTest.controllers()).hasSize(1);
+ assertThat(underTest.controllers().get(0).path()).isEqualTo("api/system");
}
@Test
public void execute_request() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "health");
+ underTest.execute(request, response, "api/system", "health", null);
assertThat(response.stream().outputAsString()).isEqualTo("good");
}
@Test
- public void execute_request_with_format_type() {
+ public void execute_request_with_action_suffix() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "health.protobuf");
+ underTest.execute(request, response, "api/system", "health", "PROTOBUF");
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");
+
+ assertThat(response.stream().httpStatus()).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();
- engine.execute(request, response, "api/system", "alive");
+ underTest.execute(request, response, "api/system", "alive", null);
assertThat(response.stream().outputAsString()).isEmpty();
}
public void bad_controller() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/xxx", "health");
+ underTest.execute(request, response, "api/xxx", "health", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown web service: api/xxx\"}]}");
}
public void bad_action() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "xxx");
+ underTest.execute(request, response, "api/system", "xxx", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown action: api/system/xxx\"}]}");
}
public void method_get_not_allowed() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "ping");
+ underTest.execute(request, response, "api/system", "ping", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method POST is required\"}]}");
}
public void method_post_required() {
ValidatingRequest request = new SimpleRequest("POST");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "ping");
+ underTest.execute(request, response, "api/system", "ping", null);
assertThat(response.stream().outputAsString()).isEqualTo("pong");
}
public void unknown_parameter_is_set() {
ValidatingRequest request = new SimpleRequest("GET").setParam("unknown", "Unknown");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "fail_with_undeclared_parameter");
+ underTest.execute(request, response, "api/system", "fail_with_undeclared_parameter", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"BUG - parameter 'unknown' is undefined for action 'fail_with_undeclared_parameter'\"}]}");
}
public void required_parameter_is_not_set() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "print");
+ underTest.execute(request, response, "api/system", "print", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"The 'message' parameter is missing\"}]}");
}
public void optional_parameter_is_not_set() {
ValidatingRequest request = new SimpleRequest("GET").setParam("message", "Hello World");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "print");
+ underTest.execute(request, response, "api/system", "print", null);
assertThat(response.stream().outputAsString()).isEqualTo("Hello World by -");
}
.setParam("message", "Hello World")
.setParam("author", "Marcel");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "print");
+ underTest.execute(request, response, "api/system", "print", null);
assertThat(response.stream().outputAsString()).isEqualTo("Hello World by Marcel");
}
.setParam("message", "Hello World")
.setParam("format", "json");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "print");
+ underTest.execute(request, response, "api/system", "print", null);
assertThat(response.stream().outputAsString()).isEqualTo("Hello World by -");
}
.setParam("message", "Hello World")
.setParam("format", "html");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "print");
+ underTest.execute(request, response, "api/system", "print", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Value of parameter 'format' (html) must be one of: [json, xml]\"}]}");
}
public void internal_error() {
ValidatingRequest request = new SimpleRequest("GET");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "fail");
+ underTest.execute(request, response, "api/system", "fail", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unexpected\"}]}");
assertThat(response.stream().httpStatus()).isEqualTo(500);
ServletResponse response = new ServletResponse();
when(i18n.message(Locale.ENGLISH, "bad.request.reason", "bad.request.reason", 0)).thenReturn("reason #0");
- engine.execute(request, response, "api/system", "fail_with_i18n_message");
+ underTest.execute(request, response, "api/system", "fail_with_i18n_message", null);
assertThat(response.stream().outputAsString()).isEqualTo(
- "{\"errors\":[{\"msg\":\"reason #0\"}]}"
- );
+ "{\"errors\":[{\"msg\":\"reason #0\"}]}");
assertThat(response.stream().httpStatus()).isEqualTo(400);
assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON);
}
ValidatingRequest request = new SimpleRequest("GET").setParam("count", "3");
ServletResponse response = new ServletResponse();
- engine.execute(request, response, "api/system", "fail_with_multiple_messages");
+ underTest.execute(request, response, "api/system", "fail_with_multiple_messages", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":["
+ "{\"msg\":\"Bad request 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");
- engine.execute(request, response, "api/system", "fail_with_multiple_i18n_messages");
+ underTest.execute(request, response, "api/system", "fail_with_multiple_i18n_messages", null);
assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[" +
"{\"msg\":\"reason #0\"}," +