diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f3a45a602..1628d676d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Detect renamed files in git and hg diffs ([#1157](https://github.com/scm-manager/scm-manager/pull/1157)) +### Fixed +- Resolved conflicting dependencies for scm-webapp ([#1159](https://github.com/scm-manager/scm-manager/pull/1159)) + ## [2.0.0-rc8] - 2020-05-08 ### Added - Add iconStyle + onClick option and story shot for icon component ([#1100](https://github.com/scm-manager/scm-manager/pull/1100)) diff --git a/Jenkinsfile b/Jenkinsfile index 7b0e8e9f08..53819fc228 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -206,6 +206,7 @@ Maven setupMavenBuild() { def logConf = "scm-webapp/src/main/resources/logback.ci.xml" mvn.additionalArgs += " -Dlogback.configurationFile=${logConf}" mvn.additionalArgs += " -Dscm-it.logbackConfiguration=${logConf}" + mvn.additionalArgs += " -Dsonar.coverage.exclusions=**/*.test.ts,**/*.test.tsx,**/*.stories.tsx" if (isMainBranch() || isReleaseBranch()) { // Release starts javadoc, which takes very long, so do only for certain branches diff --git a/pom.xml b/pom.xml index b1e63cdadc..9eed838b68 100644 --- a/pom.xml +++ b/pom.xml @@ -241,6 +241,16 @@ org.jboss.resteasy resteasy-core ${resteasy.version} + + + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.1_spec + + + org.jboss.spec.javax.xml.bind + jboss-jaxb-api_2.3_spec + + @@ -253,6 +263,12 @@ org.jboss.resteasy resteasy-jaxb-provider ${resteasy.version} + + + org.jboss.spec.javax.xml.bind + jboss-jaxb-api_2.3_spec + + @@ -267,6 +283,30 @@ ${resteasy.version} + + org.jboss.resteasy + resteasy-client-api + ${resteasy.version} + + + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.1_spec + + + + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + + + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.1_spec + + + + org.jboss.resteasy resteasy-guice @@ -277,6 +317,12 @@ org.jboss.resteasy resteasy-servlet-initializer ${resteasy.version} + + + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.1_spec + + @@ -437,8 +489,8 @@ - javax.xml.bind - jaxb-api + jakarta.xml.bind + jakarta.xml.bind-api ${jaxb.version} @@ -448,12 +500,6 @@ ${jaxb.version} - - javax.activation - activation - 1.1.1 - - @@ -901,20 +947,20 @@ 2.28.2 - 1.3 + 2.1 5.6.2 1.7.30 1.2.3 - 3.0.1 + 3.1.0 2.1.1 4.5.3.Final 1.19.4 2.11.0 4.2.3 - 2.3.1 + 2.3.2 6.1.4.Final diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 5ba07696a4..7d78979d96 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -173,8 +173,8 @@ - javax.xml.bind - jaxb-api + jakarta.xml.bind + jakarta.xml.bind-api @@ -182,11 +182,6 @@ jaxb-runtime - - javax.activation - activation - - diff --git a/scm-core/src/main/java/sonia/scm/filter/GZipResponseStream.java b/scm-core/src/main/java/sonia/scm/filter/GZipResponseStream.java index e99ccf9b80..2693fdf3b0 100644 --- a/scm-core/src/main/java/sonia/scm/filter/GZipResponseStream.java +++ b/scm-core/src/main/java/sonia/scm/filter/GZipResponseStream.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.filter; //~--- non-JDK imports -------------------------------------------------------- @@ -39,6 +39,7 @@ import java.io.IOException; import java.util.zip.GZIPOutputStream; import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; import javax.servlet.http.HttpServletResponse; /** @@ -245,6 +246,20 @@ public class GZipResponseStream extends ServletOutputStream return closed; } + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + try { + writeListener.onWritePossible(); + } catch (IOException e) { + logger.debug("could not call writeListener.onWritePossible()", e); + } + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletRequest.java b/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletRequest.java index 04f725d4ed..e674d1d2e2 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletRequest.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletRequest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web.filter; //~--- non-JDK imports -------------------------------------------------------- @@ -36,6 +36,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; @@ -197,6 +198,25 @@ public class BufferedHttpServletRequest extends HttpServletRequestWrapper return bais.read(buf, off, len); } + @Override + public boolean isFinished() { + return bais.available() == 0; + } + + @Override + public boolean isReady() { + return bais.available() > 0; + } + + @Override + public void setReadListener(ReadListener readListener) { + try { + readListener.onDataAvailable(); + } catch (IOException e) { + logger.debug("could not call readListener.onDataAvailable()", e); + } + } + //~--- fields ------------------------------------------------------------- /** Field description */ diff --git a/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletResponse.java b/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletResponse.java index 5d647659e5..0d13ed752f 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletResponse.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/BufferedHttpServletResponse.java @@ -21,11 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web.filter; //~--- JDK imports ------------------------------------------------------------ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; @@ -37,6 +40,7 @@ import java.util.Map; import java.util.Set; import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; @@ -48,6 +52,8 @@ import javax.servlet.http.HttpServletResponseWrapper; public class BufferedHttpServletResponse extends HttpServletResponseWrapper { + private static final Logger LOG = LoggerFactory.getLogger(BufferedHttpServletResponse.class); + /** * Constructs ... * @@ -445,6 +451,20 @@ public class BufferedHttpServletResponse extends HttpServletResponseWrapper baos.write(param); } + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + try { + writeListener.onWritePossible(); + } catch (IOException e) { + LOG.debug("could not call writeListener.onWritePossible()", e); + } + } + //~--- fields ------------------------------------------------------------- /** Field description */ diff --git a/scm-it/pom.xml b/scm-it/pom.xml index 146a7b33b2..bf9b4e6d78 100644 --- a/scm-it/pom.xml +++ b/scm-it/pom.xml @@ -102,7 +102,7 @@ io.rest-assured rest-assured - 3.1.0 + 4.3.0 test diff --git a/scm-it/src/test/java/sonia/scm/it/RoleITCase.java b/scm-it/src/test/java/sonia/scm/it/RoleITCase.java index e6b8ad5932..21f4c391ee 100644 --- a/scm-it/src/test/java/sonia/scm/it/RoleITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RoleITCase.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.it; import org.apache.http.HttpStatus; @@ -66,7 +66,7 @@ public class RoleITCase { given(VndMediaType.REPOSITORY_ROLE) .when() - .content("{" + + .body("{" + "\"name\": \"" + ROLE_NAME + "\"," + "\"verbs\": [\"read\",\"permissionRead\"]" + "}") @@ -84,7 +84,7 @@ public class RoleITCase { given(VndMediaType.REPOSITORY_PERMISSION) .when() - .content("{\n" + + .body("{\n" + "\t\"role\": \"" + ROLE_NAME + "\",\n" + "\t\"name\": \"" + USER + "\",\n" + "\t\"groupPermission\": false\n" + diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index 0df93cc2bd..14265c0052 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.it.utils; import io.restassured.response.ValidatableResponse; @@ -86,7 +86,7 @@ public class TestData { String admin = isAdmin ? "true" : "false"; given(VndMediaType.USER) .when() - .content(new StringBuilder() + .body(new StringBuilder() .append(" {\n") .append(" \"active\": true,\n") .append(" \"admin\": ").append(admin).append(",\n") @@ -124,7 +124,7 @@ public class TestData { LOG.info("create group with group name: {} and description {}", groupName, desc); given(VndMediaType.GROUP) .when() - .content(getGroupJson(groupName,desc)) + .body(getGroupJson(groupName,desc)) .post(getGroupsUrl()) .then() .statusCode(HttpStatus.SC_CREATED) @@ -136,7 +136,7 @@ public class TestData { LOG.info("create permission with name {} and verbs {} using the endpoint: {}", username, verbs, defaultPermissionUrl); given(VndMediaType.REPOSITORY_PERMISSION) .when() - .content("{\n" + + .body("{\n" + "\t\"verbs\": " + verbs.stream().collect(Collectors.joining("\",\"", "[\"", "\"]")) + ",\n" + "\t\"name\": \"" + username + "\",\n" + "\t\"groupPermission\": false\n" + diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java index a3f3895770..486cffde8c 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web; import org.junit.Test; @@ -33,6 +33,7 @@ import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.util.HttpUtil; import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; @@ -47,40 +48,40 @@ import static org.mockito.Mockito.when; /** * Unit tests for {@link GitPermissionFilter}. - * + * * Created by omilke on 19.05.2017. */ @RunWith(MockitoJUnitRunner.class) public class GitPermissionFilterTest { private final GitPermissionFilter permissionFilter = new GitPermissionFilter(new ScmConfiguration(), mock(ScmProviderHttpServlet.class)); - + @Mock private HttpServletResponse response; - + @Test public void testIsWriteRequest() { HttpServletRequest request = mockRequestWithMethodAndRequestURI("POST", "/scm/git/fanzy-project/git-receive-pack"); assertThat(permissionFilter.isWriteRequest(request), is(true)); - + request = mockRequestWithMethodAndRequestURI("GET", "/scm/git/fanzy-project/info/refs?service=git-receive-pack"); assertThat(permissionFilter.isWriteRequest(request), is(true)); - + request = mockRequestWithMethodAndRequestURI("GET", "/scm/git/fanzy-project/info/refs?service=some-other-service"); assertThat(permissionFilter.isWriteRequest(request), is(false)); - + request = mockRequestWithMethodAndRequestURI( - "PUT", + "PUT", "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec" ); assertThat(permissionFilter.isWriteRequest(request), is(true)); - + request = mockRequestWithMethodAndRequestURI( - "GET", + "GET", "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec" ); assertThat(permissionFilter.isWriteRequest(request), is(false)); - + request = mockRequestWithMethodAndRequestURI("POST", "/scm/git/git-lfs-demo.git/info/lfs/objects/batch"); assertThat(permissionFilter.isWriteRequest(request), is(false)); } @@ -97,45 +98,45 @@ public class GitPermissionFilterTest { @Test public void testSendNotEnoughPrivilegesErrorAsBrowser() throws IOException { HttpServletRequest request = mockGitReceivePackServiceRequest(); - + permissionFilter.sendNotEnoughPrivilegesError(request, response); - + verify(response).sendError(HttpServletResponse.SC_FORBIDDEN); } - + @Test public void testSendNotEnoughPrivilegesErrorAsGitClient() throws IOException { verifySendNotEnoughPrivilegesErrorAsGitClient("git/2.9.3"); } - + @Test public void testSendNotEnoughPrivilegesErrorAsJGitClient() throws IOException { verifySendNotEnoughPrivilegesErrorAsGitClient("JGit/4.2"); } - + private void verifySendNotEnoughPrivilegesErrorAsGitClient(String userAgent) throws IOException { HttpServletRequest request = mockGitReceivePackServiceRequest(); when(request.getHeader(HttpUtil.HEADER_USERAGENT)).thenReturn(userAgent); - + CapturingServletOutputStream stream = new CapturingServletOutputStream(); when(response.getOutputStream()).thenReturn(stream); - + permissionFilter.sendNotEnoughPrivilegesError(request, response); - + verify(response).setStatus(HttpServletResponse.SC_OK); - assertThat(stream.toString(), containsString("privileges")); + assertThat(stream.toString(), containsString("privileges")); } - + private HttpServletRequest mockGitReceivePackServiceRequest() { HttpServletRequest request = mockRequestWithMethodAndRequestURI("GET", "/git/info/refs"); when(request.getParameter("service")).thenReturn("git-receive-pack"); return request; } - + private static class CapturingServletOutputStream extends ServletOutputStream { private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - + @Override public void write(int b) throws IOException { baos.write(b); @@ -145,11 +146,21 @@ public class GitPermissionFilterTest { public void close() throws IOException { baos.close(); } - + @Override public String toString() { return baos.toString(); } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + + } } - + } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java index 9262836d85..1f435703df 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletInputStream.java @@ -21,11 +21,12 @@ * 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.base.Preconditions; +import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -76,4 +77,19 @@ public class HgServletInputStream extends ServletInputStream { public void close() throws IOException { original.close(); } + + @Override + public boolean isFinished() { + return original.isFinished(); + } + + @Override + public boolean isReady() { + return original.isReady(); + } + + @Override + public void setReadListener(ReadListener readListener) { + original.setReadListener(readListener); + } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java index b1c2ed60cd..1f06ede4c1 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/HgServletInputStreamTest.java @@ -21,13 +21,14 @@ * 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.base.Charsets; import com.google.common.io.ByteStreams; import org.junit.Test; +import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -69,6 +70,20 @@ public class HgServletInputStreamTest { public int read() { return input.read(); } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + } } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java index 80f4094d48..29bd1b41a2 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/web/WireProtocolTest.java @@ -21,7 +21,7 @@ * 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.base.Charsets; @@ -31,6 +31,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayInputStream; @@ -181,6 +182,19 @@ public class WireProtocolTest { return input.read(); } + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + } } } diff --git a/scm-plugins/scm-legacy-plugin/pom.xml b/scm-plugins/scm-legacy-plugin/pom.xml index 46bc9d99f2..0010f81b11 100644 --- a/scm-plugins/scm-legacy-plugin/pom.xml +++ b/scm-plugins/scm-legacy-plugin/pom.xml @@ -36,9 +36,9 @@ Support migrated repository urls and v1 passwords 2.0.0-SNAPSHOT smp - + - + @@ -48,13 +48,6 @@ provided - - javax.ws.rs - jsr311-api - 1.1.1 - compile - - diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index bf5fa38c28..ff4e93594d 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -146,6 +146,12 @@ ${jackson.version} + + javax.ws.rs + javax.ws.rs-api + + + @@ -197,21 +203,15 @@ - org.glassfish - javax.el - 3.0.1-b11 - - - - javax.xml.bind - jaxb-api - 2.3.1 + jakarta.xml.bind + jakarta.xml.bind-api + ${jaxb.version} org.glassfish.jaxb jaxb-runtime - 2.3.0 + ${jaxb.version} @@ -438,13 +438,6 @@ - - commons-logging - commons-logging - 1.1.3 - provided - - org.projectlombok lombok @@ -654,6 +647,20 @@ + + org.basepom.maven + duplicate-finder-maven-plugin + 1.3.0 + + false + false + false + false + true + true + false + + scm-webapp diff --git a/scm-webapp/src/main/java/sonia/scm/api/InvalidFormatExceptionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/InvalidFormatExceptionMapper.java new file mode 100644 index 0000000000..97dd96a23a --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/InvalidFormatExceptionMapper.java @@ -0,0 +1,59 @@ +/* + * 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.api; + +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import sonia.scm.api.v2.resources.ErrorDto; +import sonia.scm.web.VndMediaType; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import java.util.Collections; + +@Provider +public class InvalidFormatExceptionMapper implements ExceptionMapper { + + private static final Logger LOG = LoggerFactory.getLogger(InvalidFormatExceptionMapper.class); + + private static final String ERROR_CODE = "2qRyyaVcJ1"; + + @Override + public Response toResponse(InvalidFormatException exception) { + LOG.trace("got invalid format in json: {}", exception.getMessage()); + ErrorDto errorDto = new ErrorDto(); + errorDto.setMessage("invalid format in json content: " + exception.getMessage()); + errorDto.setContext(Collections.emptyList()); + errorDto.setErrorCode(ERROR_CODE); + errorDto.setTransactionId(MDC.get("transaction_id")); + return Response.status(Response.Status.BAD_REQUEST) + .entity(errorDto) + .type(VndMediaType.ERROR_TYPE) + .build(); + } +} diff --git a/scm-webapp/src/main/resources/locales/de/plugins.json b/scm-webapp/src/main/resources/locales/de/plugins.json index 8c5c88e0f8..314dac3de4 100644 --- a/scm-webapp/src/main/resources/locales/de/plugins.json +++ b/scm-webapp/src/main/resources/locales/de/plugins.json @@ -215,6 +215,10 @@ "8nRuFzjss1": { "displayName": "Fehler beim Löschen falscher Downloads", "description": "Ein fehlerhaft heruntergeladenes Plugin konnte nicht gelöscht werden. Bitte prüfen Sie die Server Logs und löschen die Datei manuell." + }, + "2qRyyaVcJ1": { + "displayName": "Ungültig formatiertes Element", + "description": "Die Eingabe beinhaltete unfültige Formate. Bitte prüfen Sie die Server Logs für genauere Informationen." } }, "namespaceStrategies": { diff --git a/scm-webapp/src/main/resources/locales/en/plugins.json b/scm-webapp/src/main/resources/locales/en/plugins.json index 998e796bac..fba82da650 100644 --- a/scm-webapp/src/main/resources/locales/en/plugins.json +++ b/scm-webapp/src/main/resources/locales/en/plugins.json @@ -215,6 +215,10 @@ "8nRuFzjss1": { "displayName": "Error while cleaning up failed plugin", "description": "A failed plugin download could not be removed correctly. Please check the server log and remove the plugin manually." + }, + "2qRyyaVcJ1": { + "displayName": "Invalid format in element", + "description": "The input had some invalid formats. Please check the server log for further information." } }, "namespaceStrategies": { diff --git a/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java b/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java index 3fbbfafdcd..422edb2ce5 100644 --- a/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java +++ b/scm-webapp/src/test/java/sonia/scm/ProxyPushStateDispatcherTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm; import com.google.common.base.Charsets; @@ -33,16 +33,23 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.net.HttpURLConnection; -import java.util.*; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.verify; @@ -173,7 +180,7 @@ public class ProxyPushStateDispatcherTest { private class DevServletInputStream extends ServletInputStream { - private InputStream inputStream; + private ByteArrayInputStream inputStream; private DevServletInputStream(String content) { inputStream = new ByteArrayInputStream(content.getBytes(Charsets.UTF_8)); @@ -183,6 +190,20 @@ public class ProxyPushStateDispatcherTest { public int read() throws IOException { return inputStream.read(); } + + @Override + public boolean isReady() { + return inputStream.available() > 0; + } + + @Override + public boolean isFinished() { + return inputStream.available() == 0; + } + + @Override + public void setReadListener(ReadListener readListener) { + } } private class DevServletOutputStream extends ServletOutputStream { @@ -193,6 +214,15 @@ public class ProxyPushStateDispatcherTest { public void write(int b) { stream.write(b); } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + } } } diff --git a/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java b/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java index 8364a53000..21727e56b3 100644 --- a/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java +++ b/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm; import com.google.common.base.Charsets; @@ -37,6 +37,7 @@ import sonia.scm.plugin.PluginLoader; import sonia.scm.plugin.UberWebResourceLoader; import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; @@ -152,6 +153,15 @@ public class WebResourceServletTest { public void write(int b) { buffer.write(b); } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + } } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/InvalidFormatExceptionMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/InvalidFormatExceptionMapperTest.java new file mode 100644 index 0000000000..c06da77c92 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/InvalidFormatExceptionMapperTest.java @@ -0,0 +1,74 @@ +/* + * 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.api; + +import org.jboss.resteasy.mock.MockDispatcherFactory; +import org.jboss.resteasy.mock.MockHttpRequest; +import org.jboss.resteasy.mock.MockHttpResponse; +import org.jboss.resteasy.spi.Dispatcher; +import org.junit.jupiter.api.Test; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; + +import static org.assertj.core.api.Assertions.assertThat; + +class InvalidFormatExceptionMapperTest { + + @Test + void shouldMapInvalidFormatExceptionDueToInvalidEnum() throws URISyntaxException, UnsupportedEncodingException { + Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + dispatcher.getRegistry().addSingletonResource(new SimpleResource()); + dispatcher.getProviderFactory().registerProvider(InvalidFormatExceptionMapper.class); + + MockHttpRequest request = MockHttpRequest + .post("/") + .contentType("application/json") + .content("{\"e\": \"NONE\"}".getBytes()); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + + assertThat(response.getStatus()).isEqualTo(400); + assertThat(response.getContentAsString()).contains("2qRyyaVcJ1"); + } + + @Path("/") + static class SimpleResource { + @POST + public void post(ObjectWithEnum o) { + } + } + + static class ObjectWithEnum { + public Enum e; + } + + enum Enum { + ONE, TWO + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/lifecycle/RestartServletTest.java b/scm-webapp/src/test/java/sonia/scm/lifecycle/RestartServletTest.java index 324f43dcb7..eeae7c697a 100644 --- a/scm-webapp/src/test/java/sonia/scm/lifecycle/RestartServletTest.java +++ b/scm-webapp/src/test/java/sonia/scm/lifecycle/RestartServletTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.lifecycle; import com.github.legman.Subscribe; @@ -34,6 +34,7 @@ import sonia.scm.Stage; import sonia.scm.event.ScmEventBus; import sonia.scm.event.ScmTestEventBus; +import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -128,6 +129,21 @@ public class RestartServletTest { private ServletInputStream createServletInputStream(final InputStream inputStream) { return new ServletInputStream() { + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + @Override public int read() throws IOException { return inputStream.read();