diff --git a/library/src/androidTest/java/com/owncloud/android/ExceptionParserIT.java b/library/src/androidTest/java/com/owncloud/android/ExceptionParserIT.java deleted file mode 100644 index 017e9e589a..0000000000 --- a/library/src/androidTest/java/com/owncloud/android/ExceptionParserIT.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Nextcloud Android Library - * - * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-FileCopyrightText: 2018-2022 Tobias Kaminsky - * SPDX-License-Identifier: MIT - */ -package com.owncloud.android; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.owncloud.android.lib.common.operations.ExceptionParser; - -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - - -/** - * Created by tobi on 3/21/18. - */ - -public class ExceptionParserIT { - - @Test - public void testVirusException() throws IOException { - String virusException = "\n" + - "\n" + - " OCA\\DAV\\Connector\\Sabre\\Exception\\UnsupportedMediaType" + - "\n" + - " Virus Eicar-Test-Signature is detected in the file. " + - "Upload cannot be completed.\n" + - ""; - - InputStream is = new ByteArrayInputStream(virusException.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - - assertTrue(xmlParser.isVirusException()); - assertFalse(xmlParser.isInvalidCharacterException()); - } - - @Test - public void testInvalidCharacterException() throws IOException { - String virusException = "\n" + - "\n" + - " OC\\Connector\\Sabre\\Exception\\InvalidPath\n" + - " Wrong Path\n" + - ""; - - InputStream is = new ByteArrayInputStream(virusException.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - - assertTrue(xmlParser.isInvalidCharacterException()); - assertFalse(xmlParser.isVirusException()); - } - - @Test - public void testInvalidCharacterUploadException() throws IOException { - String virusException = "\n" + - "\n" + - " OCP\\Files\\InvalidPathException\n" + - " Wrong Path\n" + - ""; - - InputStream is = new ByteArrayInputStream(virusException.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - - assertTrue(xmlParser.isInvalidCharacterException()); - assertFalse(xmlParser.isVirusException()); - } - - @Test - public void testEmptyString() throws IOException { - String emptyString = ""; - - InputStream is = new ByteArrayInputStream(emptyString.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - - assertFalse(xmlParser.isVirusException()); - assertFalse(xmlParser.isInvalidCharacterException()); - } - - @Test - public void testString() throws IOException { - String emptyString = ""; - - InputStream is = new ByteArrayInputStream(emptyString.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - - assertFalse(xmlParser.isVirusException()); - assertFalse(xmlParser.isInvalidCharacterException()); - } -} diff --git a/library/src/androidTest/java/com/owncloud/android/ResponseFormatDetectorTests.kt b/library/src/androidTest/java/com/owncloud/android/ResponseFormatDetectorTests.kt new file mode 100644 index 0000000000..37996adf32 --- /dev/null +++ b/library/src/androidTest/java/com/owncloud/android/ResponseFormatDetectorTests.kt @@ -0,0 +1,45 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android + +import com.owncloud.android.lib.common.utils.responseFormat.ResponseFormat +import com.owncloud.android.lib.common.utils.responseFormat.ResponseFormatDetector +import junit.framework.TestCase.assertEquals +import org.junit.Test + +class ResponseFormatDetectorTests { + @Test + fun testJsonDetection() { + val json = """{ "name": "Alice", "age": 30 }""" + assertEquals(ResponseFormat.JSON, ResponseFormatDetector.detectFormat(json)) + } + + @Test + fun testJsonArrayDetection() { + val jsonArray = """[{"name": "Alice"}, {"name": "Bob"}]""" + assertEquals(ResponseFormat.JSON, ResponseFormatDetector.detectFormat(jsonArray)) + } + + @Test + fun testXmlDetection() { + val xml = """Alice30""" + assertEquals(ResponseFormat.XML, ResponseFormatDetector.detectFormat(xml)) + } + + @Test + fun testInvalidFormat() { + val invalid = "Just a plain string" + assertEquals(ResponseFormat.UNKNOWN, ResponseFormatDetector.detectFormat(invalid)) + } + + @Test + fun testEmptyString() { + val empty = "" + assertEquals(ResponseFormat.UNKNOWN, ResponseFormatDetector.detectFormat(empty)) + } +} diff --git a/library/src/androidTest/java/com/owncloud/android/XMLExceptionParserTests.kt b/library/src/androidTest/java/com/owncloud/android/XMLExceptionParserTests.kt new file mode 100644 index 0000000000..15983fc6d8 --- /dev/null +++ b/library/src/androidTest/java/com/owncloud/android/XMLExceptionParserTests.kt @@ -0,0 +1,75 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: MIT + */ +package com.owncloud.android + +import com.owncloud.android.lib.common.operations.XMLExceptionParser +import org.junit.Assert +import org.junit.Test +import java.io.ByteArrayInputStream + +class XMLExceptionParserTests { + @Test + fun testVirusException() { + val virusException = + "\n" + + "\n" + + " OCA\\DAV\\Connector\\Sabre\\Exception\\UnsupportedMediaType" + + "\n" + + " Virus Eicar-Test-Signature is detected in the file. " + + "Upload cannot be completed.\n" + + "" + + val inputStream = ByteArrayInputStream(virusException.toByteArray()) + val xmlParser = XMLExceptionParser(inputStream) + + Assert.assertTrue(xmlParser.isVirusException) + Assert.assertFalse(xmlParser.isInvalidCharacterException) + } + + @Test + fun testInvalidCharacterException() { + val virusException = + "\n" + + "\n" + + " OC\\Connector\\Sabre\\Exception\\InvalidPath\n" + + " Wrong Path\n" + + "" + + val inputStream = ByteArrayInputStream(virusException.toByteArray()) + val xmlParser = XMLExceptionParser(inputStream) + + Assert.assertTrue(xmlParser.isInvalidCharacterException) + Assert.assertFalse(xmlParser.isVirusException) + } + + @Test + fun testInvalidCharacterUploadException() { + val virusException = + "\n" + + "\n" + + " OCP\\Files\\InvalidPathException\n" + + " Wrong Path\n" + + "" + + val inputStream = ByteArrayInputStream(virusException.toByteArray()) + val xmlParser = XMLExceptionParser(inputStream) + + Assert.assertTrue(xmlParser.isInvalidCharacterException) + Assert.assertFalse(xmlParser.isVirusException) + } + + @Test + fun testEmptyString() { + val emptyString = "" + + val inputStream = ByteArrayInputStream(emptyString.toByteArray()) + val xmlParser = XMLExceptionParser(inputStream) + + Assert.assertFalse(xmlParser.isVirusException) + Assert.assertFalse(xmlParser.isInvalidCharacterException) + } +} diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 5f281a80dc..0441e588b8 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -30,6 +30,8 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.common.utils.responseFormat.ResponseFormat; +import com.owncloud.android.lib.common.utils.responseFormat.ResponseFormatDetector; import com.owncloud.android.lib.resources.files.CreateLocalFileException; import org.apache.commons.httpclient.ConnectTimeoutException; @@ -235,10 +237,13 @@ public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) switch (httpCode) { case HttpStatus.SC_BAD_REQUEST: try { - InputStream is = new ByteArrayInputStream(bodyResponse.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); - if (xmlParser.isInvalidCharacterException()) { - mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER; + if (!bodyResponse.isEmpty() && + ResponseFormatDetector.INSTANCE.detectFormat(bodyResponse) == ResponseFormat.XML) { + InputStream is = new ByteArrayInputStream(bodyResponse.getBytes()); + XMLExceptionParser xmlParser = new XMLExceptionParser(is); + if (xmlParser.isInvalidCharacterException()) { + mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER; + } } } catch (Exception e) { mCode = ResultCode.UNHANDLED_HTTP_CODE; @@ -336,9 +341,11 @@ public RemoteOperationResult(boolean success, HttpMethod httpMethod) { try { String bodyResponse = httpMethod.getResponseBodyAsString(); - if (bodyResponse != null && bodyResponse.length() > 0) { + if (bodyResponse != null + && !bodyResponse.isEmpty() && + ResponseFormatDetector.INSTANCE.detectFormat(bodyResponse) == ResponseFormat.XML) { InputStream is = new ByteArrayInputStream(bodyResponse.getBytes()); - ExceptionParser xmlParser = new ExceptionParser(is); + XMLExceptionParser xmlParser = new XMLExceptionParser(is); if (xmlParser.isInvalidCharacterException()) { mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER; diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java b/library/src/main/java/com/owncloud/android/lib/common/operations/XMLExceptionParser.java similarity index 91% rename from library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java rename to library/src/main/java/com/owncloud/android/lib/common/operations/XMLExceptionParser.java index 9fcb55ce33..7f458d577e 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/XMLExceptionParser.java @@ -24,8 +24,8 @@ * * @author masensio, tobiaskaminsky */ -public class ExceptionParser { - private static final String TAG = ExceptionParser.class.getSimpleName(); +public class XMLExceptionParser { + private static final String TAG = XMLExceptionParser.class.getSimpleName(); private static final String INVALID_PATH_EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath"; private static final String INVALID_PATH_EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException"; @@ -46,25 +46,20 @@ public class ExceptionParser { /** * Parse is as an Invalid Path Exception * - * @param is InputStream xml - * @return if The exception is an Invalid Char Exception - * @throws IOException + * @param inputStream InputStream xml */ - public ExceptionParser(InputStream is) throws IOException { - try { - // XMLPullParser + public XMLExceptionParser(InputStream inputStream) { + try (inputStream) { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - parser.setInput(is, null); + parser.setInput(inputStream, null); parser.nextTag(); readError(parser); } catch (Exception e) { Log_OC.e(TAG, "Error parsing exception: " + e.getMessage()); - } finally { - is.close(); } } diff --git a/library/src/main/java/com/owncloud/android/lib/common/utils/responseFormat/ResponseFormat.kt b/library/src/main/java/com/owncloud/android/lib/common/utils/responseFormat/ResponseFormat.kt new file mode 100644 index 0000000000..c7c3f3f555 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/common/utils/responseFormat/ResponseFormat.kt @@ -0,0 +1,14 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.common.utils.responseFormat + +enum class ResponseFormat { + JSON, + XML, + UNKNOWN +} diff --git a/library/src/main/java/com/owncloud/android/lib/common/utils/responseFormat/ResponseFormatDetector.kt b/library/src/main/java/com/owncloud/android/lib/common/utils/responseFormat/ResponseFormatDetector.kt new file mode 100644 index 0000000000..ed77deb9ad --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/common/utils/responseFormat/ResponseFormatDetector.kt @@ -0,0 +1,54 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.common.utils.responseFormat + +import com.owncloud.android.lib.common.utils.Log_OC +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import java.io.ByteArrayInputStream +import javax.xml.parsers.DocumentBuilderFactory + +object ResponseFormatDetector { + private const val TAG = "ResponseFormatDetector" + + fun detectFormat(input: String): ResponseFormat = + when { + isJSON(input) -> ResponseFormat.JSON + isXML(input) -> ResponseFormat.XML + else -> ResponseFormat.UNKNOWN + } + + private fun isJSON(input: String): Boolean = + try { + JSONObject(input) + true + } catch (e: JSONException) { + try { + Log_OC.i(TAG, "Info it's not JSONObject: $e") + JSONArray(input) + true + } catch (e: JSONException) { + Log_OC.e(TAG, "Exception it's not JSONArray: $e") + false + } + } + + @Suppress("TooGenericExceptionCaught") + private fun isXML(input: String): Boolean = + try { + val factory = DocumentBuilderFactory.newInstance() + val builder = factory.newDocumentBuilder() + val stream = ByteArrayInputStream(input.toByteArray()) + builder.parse(stream) + true + } catch (e: Exception) { + Log_OC.e(TAG, "Exception isXML: $e") + false + } +}