Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <[email protected]>
* 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 = """<person><name>Alice</name><age>30</age></person>"""
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))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <[email protected]>
* 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 =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<d:error xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\">\n" +
" <s:exception>OCA\\DAV\\Connector\\Sabre\\Exception\\UnsupportedMediaType" +
"</s:exception>\n" +
" <s:message>Virus Eicar-Test-Signature is detected in the file. " +
"Upload cannot be completed.</s:message>\n" +
"</d:error>"

val inputStream = ByteArrayInputStream(virusException.toByteArray())
val xmlParser = XMLExceptionParser(inputStream)

Assert.assertTrue(xmlParser.isVirusException)
Assert.assertFalse(xmlParser.isInvalidCharacterException)
}

@Test
fun testInvalidCharacterException() {
val virusException =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<d:error xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\">\n" +
" <s:exception>OC\\Connector\\Sabre\\Exception\\InvalidPath</s:exception>\n" +
" <s:message>Wrong Path</s:message>\n" +
"</d:error>"

val inputStream = ByteArrayInputStream(virusException.toByteArray())
val xmlParser = XMLExceptionParser(inputStream)

Assert.assertTrue(xmlParser.isInvalidCharacterException)
Assert.assertFalse(xmlParser.isVirusException)
}

@Test
fun testInvalidCharacterUploadException() {
val virusException =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<d:error xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\">\n" +
" <s:exception>OCP\\Files\\InvalidPathException</s:exception>\n" +
" <s:message>Wrong Path</s:message>\n" +
"</d:error>"

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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <[email protected]>
* SPDX-License-Identifier: MIT
*/

package com.owncloud.android.lib.common.utils.responseFormat

enum class ResponseFormat {
JSON,
XML,
UNKNOWN
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 Alper Ozturk <[email protected]>
* 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
}
}
Loading