1
0
mirror of https://github.com/owncloud/android-library.git synced 2026-08-19 12:23:00 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mendhak
2016-01-30 08:34:24 +00:00
54 changed files with 4276 additions and 493 deletions
@@ -49,13 +49,15 @@ import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
public class OwnCloudClient extends HttpClient {
private static final String TAG = OwnCloudClient.class.getSimpleName();
private static final int MAX_REDIRECTIONS_COUNT = 3;
public static final int MAX_REDIRECTIONS_COUNT = 3;
private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
@@ -67,6 +69,8 @@ public class OwnCloudClient extends HttpClient {
private int mInstanceNumber = 0;
private Uri mBaseUri;
private OwnCloudVersion mVersion = null;
/**
* Constructor
@@ -168,13 +172,13 @@ public class OwnCloudClient extends HttpClient {
*
* The timeouts are both in milliseconds; 0 means 'infinite';
* < 0 means 'do not change the default'
*
*
* @param method HTTP method request.
* @param readTimeout Timeout to set for data reception
* @param connectionTimeout Timeout to set for connection establishment
*/
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout)
throws HttpException, IOException {
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws IOException {
int oldSoTimeout = getParams().getSoTimeout();
int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
try {
@@ -191,55 +195,53 @@ public class OwnCloudClient extends HttpClient {
getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
}
}
@Override
public int executeMethod(HttpMethod method) throws IOException, HttpException {
try { // just to log
boolean customRedirectionNeeded = false;
try {
method.setFollowRedirects(mFollowRedirects);
} catch (Exception e) {
/*
if (mFollowRedirects)
Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName()
+ " method, custom redirection will be used if needed");
*/
customRedirectionNeeded = mFollowRedirects;
}
/**
* Requests the received method.
*
* Executes the method through the inherited HttpClient.executedMethod(method).
*
* @param method HTTP method request.
*/
@Override
public int executeMethod(HttpMethod method) throws IOException {
try {
// Update User Agent
HttpParams params = method.getParams();
String userAgent = OwnCloudClientManagerFactory.getUserAgent();
params.setParameter(HttpMethodParams.USER_AGENT, userAgent);
Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " +
method.getName() + " " + method.getPath());
Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " +
method.getName() + " " + method.getPath());
// logCookiesAtRequest(method.getRequestHeaders(), "before");
// logCookiesAtState("before");
int status = super.executeMethod(method);
if (customRedirectionNeeded) {
status = patchRedirection(status, method);
}
method.setFollowRedirects(false);
int status = super.executeMethod(method);
if (mFollowRedirects) {
status = followRedirection(method).getLastStatus();
}
// logCookiesAtRequest(method.getRequestHeaders(), "after");
// logCookiesAtState("after");
// logSetCookiesAtResponse(method.getResponseHeaders());
return status;
return status;
} catch (IOException e) {
Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
throw e;
//Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
throw e;
}
}
private int patchRedirection(int status, HttpMethod method) throws HttpException, IOException {
public RedirectionPath followRedirection(HttpMethod method) throws IOException {
int redirectionsCount = 0;
int status = method.getStatusCode();
RedirectionPath result = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
( status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
@@ -254,18 +256,20 @@ public class OwnCloudClient extends HttpClient {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + location.getValue());
String locationStr = location.getValue();
result.addLocation(locationStr);
// Release the connection to avoid reach the max number of connections per host
// due to it will be set a different url
exhaustResponse(method.getResponseBodyAsStream());
method.releaseConnection();
method.setURI(new URI(location.getValue(), true));
method.setURI(new URI(locationStr, true));
Header destination = method.getRequestHeader("Destination");
if (destination == null) {
destination = method.getRequestHeader("destination");
}
if (destination != null) {
String locationStr = location.getValue();
int suffixIndex = locationStr.lastIndexOf(
(mCredentials instanceof OwnCloudBearerCredentials) ?
AccountUtils.ODAV_PATH :
@@ -281,6 +285,7 @@ public class OwnCloudClient extends HttpClient {
method.setRequestHeader(destination);
}
status = super.executeMethod(method);
result.addStatus(status);
redirectionsCount++;
} else {
@@ -288,7 +293,7 @@ public class OwnCloudClient extends HttpClient {
status = HttpStatus.SC_NOT_FOUND;
}
}
return status;
return result;
}
/**
@@ -356,7 +361,10 @@ public class OwnCloudClient extends HttpClient {
mFollowRedirects = followRedirects;
}
public boolean getFollowRedirects() {
return mFollowRedirects;
}
private void logCookiesAtRequest(Header[] headers, String when) {
int counter = 0;
for (int i=0; i<headers.length; i++) {
@@ -436,4 +444,11 @@ public class OwnCloudClient extends HttpClient {
}
public void setOwnCloudVersion(OwnCloudVersion version){
mVersion = version;
}
public OwnCloudVersion getOwnCloudVersion(){
return mVersion;
}
}
@@ -82,8 +82,9 @@ public class OwnCloudClientFactory {
boolean isSamlSso =
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
if (isOauth2) {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
@@ -100,11 +101,10 @@ public class OwnCloudClientFactory {
false);
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
//String password = am.getPassword(account);
String password = am.blockingGetAuthToken(
account,
@@ -136,7 +136,8 @@ public class OwnCloudClientFactory {
boolean isSamlSso =
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
@@ -166,12 +167,11 @@ public class OwnCloudClientFactory {
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) throw new AuthenticatorException("WTF!");
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
//String password = am.getPassword(account);
//String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(),
// false);
@@ -36,8 +36,8 @@ public class OwnCloudCredentialsFactory {
return new OwnCloudBearerCredentials(authToken);
}
public static OwnCloudCredentials newSamlSsoCredentials(String sessionCookie) {
return new OwnCloudSamlSsoCredentials(sessionCookie);
public static OwnCloudCredentials newSamlSsoCredentials(String username, String sessionCookie) {
return new OwnCloudSamlSsoCredentials(username, sessionCookie);
}
public static final OwnCloudCredentials getAnonymousCredentials() {
@@ -30,9 +30,11 @@ import android.net.Uri;
public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
private String mUsername;
private String mSessionCookie;
public OwnCloudSamlSsoCredentials(String sessionCookie) {
public OwnCloudSamlSsoCredentials(String username, String sessionCookie) {
mUsername = username != null ? username : "";
mSessionCookie = sessionCookie != null ? sessionCookie : "";
}
@@ -63,8 +65,8 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
@Override
public String getUsername() {
// its unknown
return null;
// not relevant for authentication, but relevant for informational purposes
return mUsername;
}
@Override
@@ -167,7 +167,9 @@ public class AccountUtils {
boolean isSamlSso = am.getUserData(
account,
AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
String username = account.name.substring(0, account.name.lastIndexOf('@'));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
@@ -182,10 +184,9 @@ public class AccountUtils {
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken);
} else {
String username = account.name.substring(0, account.name.lastIndexOf('@'));
String password = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
@@ -199,7 +200,7 @@ public class AccountUtils {
}
public static String buildAccountName(Uri serverBaseUrl, String username) {
public static String buildAccountNameOld(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
@@ -209,7 +210,21 @@ public class AccountUtils {
}
return accountName;
}
public static String buildAccountName(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
// Remove http:// or https://
String url = serverBaseUrl.toString();
if (url.contains("://")) {
url = url.substring(serverBaseUrl.toString().indexOf("://") + 3);
}
String accountName = username + "@" + url;
return accountName;
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
@@ -336,12 +351,18 @@ public class AccountUtils {
public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
/**
* Flag signaling if the ownCloud server supports Share API"
*/
* @deprecated
*/
public static final String KEY_SUPPORTS_SHARE_API = "oc_supports_share_api";
/**
* OC accout cookies
* OC account cookies
*/
public static final String KEY_COOKIES = "oc_account_cookies";
}
/**
* OC account version
*/
public static final String KEY_OC_ACCOUNT_VERSION = "oc_account_version";
}
}
@@ -0,0 +1,127 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
*
* Copyright (C) 2015 ownCloud Inc.
*
* 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 com.owncloud.android.lib.common.network;
import org.apache.http.HttpStatus;
import java.util.Arrays;
/**
* Aggregate saving the list of URLs followed in a sequence of redirections during the exceution of a
* {@link com.owncloud.android.lib.common.operations.RemoteOperation}, and the status codes corresponding to all
* of them.
*
* The last status code saved corresponds to the first response not being a redirection, unless the sequence exceeds
* the maximum length of redirections allowed by the {@link com.owncloud.android.lib.common.OwnCloudClient} instance
* that ran the operation.
*
* If no redirection was followed, the last (and first) status code contained corresponds to the original URL in the
* request.
*/
public class RedirectionPath {
private int[] mStatuses = null;
private int mLastStatus = -1;
private String[] mLocations = null;
private int mLastLocation = -1;
private int maxRedirections;
/**
* Public constructor.
*
* @param status Status code resulting of executing a request on the original URL.
* @param maxRedirections Maximum number of redirections that will be contained.
* @throws IllegalArgumentException If 'maxRedirections' is < 0
*/
public RedirectionPath(int status, int maxRedirections) {
if (maxRedirections < 0) {
throw new IllegalArgumentException("maxRedirections MUST BE zero or greater");
}
mStatuses = new int[maxRedirections + 1];
Arrays.fill(mStatuses, -1);
mStatuses[++mLastStatus] = status;
}
/**
* Adds a new location URL to the list of followed redirections.
*
* @param location URL extracted from a 'Location' header in a redirection.
*/
public void addLocation(String location) {
if (mLocations == null) {
mLocations = new String[mStatuses.length - 1];
}
if (mLastLocation < mLocations.length - 1) {
mLocations[++mLastLocation] = location;
}
}
/**
* Adds a new status code to the list of status corresponding to followed redirections.
*
* @param status Status code from the response of another followed redirection.
*/
public void addStatus(int status) {
if (mLastStatus < mStatuses.length - 1) {
mStatuses[++mLastStatus] = status;
}
}
/**
* @return Last status code saved.
*/
public int getLastStatus() {
return mStatuses[mLastStatus];
}
/**
* @return Last location followed corresponding to a permanent redirection (status code 301).
*/
public String getLastPermanentLocation() {
for (int i = mLastStatus; i >= 0; i--) {
if (mStatuses[i] == HttpStatus.SC_MOVED_PERMANENTLY && i <= mLastLocation) {
return mLocations[i];
}
}
return null;
}
/**
* @return Count of locations.
*/
public int getRedirectionsCount() {
return mLastLocation + 1;
}
}
@@ -24,6 +24,7 @@
package com.owncloud.android.lib.common.network;
import java.math.BigDecimal;
import java.util.Date;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
@@ -37,6 +38,9 @@ import android.net.Uri;
import com.owncloud.android.lib.common.utils.Log_OC;
public class WebdavEntry {
private static final String TAG = WebdavEntry.class.getSimpleName();
public static final String NAMESPACE_OC = "http://owncloud.org/ns";
public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
@@ -49,7 +53,7 @@ public class WebdavEntry {
private String mName, mPath, mUri, mContentType, mEtag, mPermissions, mRemoteId;
private long mContentLength, mCreateTimestamp, mModifiedTimestamp, mSize;
private long mQuotaUsedBytes, mQuotaAvailableBytes;
private BigDecimal mQuotaUsedBytes, mQuotaAvailableBytes;
public WebdavEntry(MultiStatusResponse ms, String splitElement) {
resetData();
@@ -125,20 +129,37 @@ public class WebdavEntry {
prop = propSet.get(DavPropertyName.GETETAG);
if (prop != null) {
mEtag = (String) prop.getValue();
mEtag = mEtag.substring(1, mEtag.length()-1);
mEtag = WebdavUtils.parseEtag(mEtag);
}
// {DAV:}quota-used-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_USED_BYTES));
if (prop != null) {
mQuotaUsedBytes = Long.parseLong((String) prop.getValue());
String quotaUsedBytesSt = (String) prop.getValue();
try {
mQuotaUsedBytes = new BigDecimal(quotaUsedBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaUsedBytes - NumberFormatException");
} catch (NullPointerException e ){
Log_OC.w(TAG, "No value for QuotaUsedBytes - NullPointerException");
}
Log_OC.d(TAG , "QUOTA_USED_BYTES " + quotaUsedBytesSt );
}
// {DAV:}quota-available-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_AVAILABLE_BYTES));
if (prop != null) {
mQuotaAvailableBytes = Long.parseLong((String) prop.getValue());
String quotaAvailableBytesSt = (String) prop.getValue();
try {
mQuotaAvailableBytes = new BigDecimal(quotaAvailableBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaAvailableBytes - NumberFormatException");
} catch (NullPointerException e ){
Log_OC.w(TAG, "No value for QuotaAvailableBytes");
}
Log_OC.d(TAG , "QUOTA_AVAILABLE_BYTES " + quotaAvailableBytesSt );
}
// OC permissions property <oc:permissions>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_PERMISSIONS, Namespace.getNamespace(NAMESPACE_OC)
@@ -222,11 +243,11 @@ public class WebdavEntry {
return mSize;
}
public long quotaUsedBytes() {
public BigDecimal quotaUsedBytes() {
return mQuotaUsedBytes;
}
public long quotaAvailableBytes() {
public BigDecimal quotaAvailableBytes() {
return mQuotaAvailableBytes;
}
@@ -234,7 +255,7 @@ public class WebdavEntry {
mName = mUri = mContentType = mPermissions = null; mRemoteId = null;
mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
mSize = 0;
mQuotaUsedBytes = 0;
mQuotaAvailableBytes = 0;
mQuotaUsedBytes = null;
mQuotaAvailableBytes = null;
}
}
@@ -32,6 +32,8 @@ import java.util.Locale;
import android.net.Uri;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.xml.Namespace;
@@ -131,4 +133,47 @@ public class WebdavUtils {
return propSet;
}
/**
*
* @param rawEtag
* @return
*/
public static String parseEtag(String rawEtag) {
if (rawEtag == null || rawEtag.length() == 0) {
return "";
}
if (rawEtag.endsWith("-gzip")) {
rawEtag = rawEtag.substring(0, rawEtag.length() - 5);
}
if (rawEtag.length() >= 2 && rawEtag.startsWith("\"") && rawEtag.endsWith("\"")) {
rawEtag = rawEtag.substring(1, rawEtag.length() - 1);
}
return rawEtag;
}
/**
*
* @param method
* @return
*/
public static String getEtagFromResponse(HttpMethod method) {
Header eTag = method.getResponseHeader("OC-ETag");
if (eTag == null) {
eTag = method.getResponseHeader("oc-etag");
}
if (eTag == null) {
eTag = method.getResponseHeader("ETag");
}
if (eTag == null) {
eTag = method.getResponseHeader("etag");
}
String result = "";
if (eTag != null) {
result = parseEtag(eTag.getValue());
}
return result;
}
}
@@ -0,0 +1,146 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2015 ownCloud Inc.
*
* 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 com.owncloud.android.lib.common.operations;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
/**
* Parser for Invalid Character server exception
* @author masensio
*/
public class InvalidCharacterExceptionParser {
private static final String EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath";
private static final String EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException";
// No namespaces
private static final String ns = null;
// Nodes for XML Parser
private static final String NODE_ERROR = "d:error";
private static final String NODE_EXCEPTION = "s:exception";
/**
* Parse is as an Invalid Path Exception
* @param is
* @return if The exception is an Invalid Char Exception
* @throws XmlPullParserException
* @throws IOException
*/
public boolean parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
boolean result = false;
try {
// XMLPullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);
parser.nextTag();
result = readError(parser);
} finally {
is.close();
}
return result;
}
/**
* Parse OCS node
* @param parser
* @return List of ShareRemoteFiles
* @throws XmlPullParserException
* @throws IOException
*/
private boolean readError (XmlPullParser parser) throws XmlPullParserException, IOException {
String exception = "";
parser.require(XmlPullParser.START_TAG, ns , NODE_ERROR);
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// read NODE_EXCEPTION
if (name.equalsIgnoreCase(NODE_EXCEPTION)) {
exception = readText(parser);
} else {
skip(parser);
}
}
return exception.equalsIgnoreCase(EXCEPTION_STRING) ||
exception.equalsIgnoreCase(EXCEPTION_UPLOAD_STRING);
}
/**
* Skip tags in parser procedure
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
/**
* Read the text from a node
* @param parser
* @return Text of the node
* @throws IOException
* @throws XmlPullParserException
*/
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
}
@@ -24,8 +24,6 @@
package com.owncloud.android.lib.common.operations;
import java.io.IOException;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
@@ -42,6 +40,8 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
/**
* Operation which execution involves one or several interactions with an ownCloud server.
@@ -24,15 +24,21 @@
package com.owncloud.android.lib.common.operations;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountsException;
import javax.net.ssl.SSLException;
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 org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.Header;
@@ -41,60 +47,55 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.json.JSONException;
import android.accounts.Account;
import android.accounts.AccountsException;
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 javax.net.ssl.SSLException;
/**
* The result of a remote operation required to an ownCloud server.
*
* <p/>
* Provides a common classification of remote operation results for all the
* application.
*
*
* @author David A. Velasco
*/
public class RemoteOperationResult implements Serializable {
/** Generated - should be refreshed every time the class changes!! */;
private static final long serialVersionUID = -9003837206000993465L;
private static final String TAG = "RemoteOperationResult";
public enum ResultCode {
private static final long serialVersionUID = 1129130415603799707L;
private static final String TAG = RemoteOperationResult.class.getSimpleName();
public enum ResultCode {
OK,
OK_SSL,
OK_NO_SSL,
UNHANDLED_HTTP_CODE,
UNAUTHORIZED,
FILE_NOT_FOUND,
INSTANCE_NOT_CONFIGURED,
UNKNOWN_ERROR,
WRONG_CONNECTION,
TIMEOUT,
INCORRECT_ADDRESS,
HOST_NOT_AVAILABLE,
NO_NETWORK_CONNECTION,
UNAUTHORIZED,
FILE_NOT_FOUND,
INSTANCE_NOT_CONFIGURED,
UNKNOWN_ERROR,
WRONG_CONNECTION,
TIMEOUT,
INCORRECT_ADDRESS,
HOST_NOT_AVAILABLE,
NO_NETWORK_CONNECTION,
SSL_ERROR,
SSL_RECOVERABLE_PEER_UNVERIFIED,
BAD_OC_VERSION,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
INVALID_OVERWRITE,
CONFLICT,
CONFLICT,
OAUTH2_ERROR,
SYNC_CONFLICT,
LOCAL_STORAGE_FULL,
LOCAL_STORAGE_NOT_MOVED,
LOCAL_STORAGE_NOT_COPIED,
LOCAL_STORAGE_FULL,
LOCAL_STORAGE_NOT_MOVED,
LOCAL_STORAGE_NOT_COPIED,
OAUTH2_ERROR_ACCESS_DENIED,
QUOTA_EXCEEDED,
ACCOUNT_NOT_FOUND,
ACCOUNT_EXCEPTION,
ACCOUNT_NOT_NEW,
QUOTA_EXCEEDED,
ACCOUNT_NOT_FOUND,
ACCOUNT_EXCEPTION,
ACCOUNT_NOT_NEW,
ACCOUNT_NOT_THE_SAME,
INVALID_CHARACTER_IN_NAME,
SHARE_NOT_FOUND,
@@ -102,8 +103,12 @@ public class RemoteOperationResult implements Serializable {
FORBIDDEN,
SHARE_FORBIDDEN,
OK_REDIRECT_TO_NON_SECURE_CONNECTION,
INVALID_MOVE_INTO_DESCENDANT,
PARTIAL_MOVE_DONE
INVALID_MOVE_INTO_DESCENDANT,
INVALID_COPY_INTO_DESCENDANT,
PARTIAL_MOVE_DONE,
PARTIAL_COPY_DONE,
SHARE_WRONG_PARAMETER,
WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER
}
private boolean mSuccess = false;
@@ -112,12 +117,15 @@ public class RemoteOperationResult implements Serializable {
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
private String mRedirectedLocation;
private String mAuthenticate;
private String mLastPermanentLocation = null;
private ArrayList<Object> mData;
public RemoteOperationResult(ResultCode code) {
mCode = code;
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL || code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL ||
code == ResultCode.OK_NO_SSL ||
code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mData = null;
}
@@ -147,31 +155,63 @@ public class RemoteOperationResult implements Serializable {
break;
case HttpStatus.SC_FORBIDDEN:
mCode = ResultCode.FORBIDDEN;
break;
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode);
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
httpCode);
}
}
}
public RemoteOperationResult(boolean success, int httpCode, Header[] headers) {
this(success, httpCode);
if (headers != null) {
Header current;
for (int i=0; i<headers.length; i++) {
for (int i = 0; i < headers.length; i++) {
current = headers[i];
if ("location".equals(current.getName().toLowerCase())) {
mRedirectedLocation = current.getValue();
continue;
}
if ("www-authenticate".equals(current.getName().toLowerCase())) {
mAuthenticate = current.getValue();
continue;
mAuthenticate = current.getValue();
continue;
}
}
}
}
}
public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) {
mSuccess = success;
mHttpCode = httpCode;
if (success) {
mCode = ResultCode.OK;
} else if (httpCode > 0) {
switch (httpCode) {
case HttpStatus.SC_BAD_REQUEST:
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
try {
if (xmlParser.parseXMLResponse(is))
mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
} catch (Exception e) {
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.e(TAG, "Exception reading exception from server", e);
}
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE;
Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
httpCode);
}
}
}
public RemoteOperationResult(Exception e) {
mException = e;
@@ -196,10 +236,10 @@ public class RemoteOperationResult implements Serializable {
} else if (e instanceof AccountNotFoundException) {
mCode = ResultCode.ACCOUNT_NOT_FOUND;
} else if (e instanceof AccountsException) {
mCode = ResultCode.ACCOUNT_EXCEPTION;
} else if (e instanceof SSLException || e instanceof RuntimeException) {
CertificateCombinedException se = getCertificateCombinedException(e);
if (se != null) {
@@ -221,14 +261,14 @@ public class RemoteOperationResult implements Serializable {
}
public void setData(ArrayList<Object> files){
mData = files;
public void setData(ArrayList<Object> files) {
mData = files;
}
public ArrayList<Object> getData(){
return mData;
}
public ArrayList<Object> getData() {
return mData;
}
public boolean isSuccess() {
return mSuccess;
}
@@ -253,9 +293,9 @@ public class RemoteOperationResult implements Serializable {
return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
}
public boolean isRedirectToNonSecureConnection() {
return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION;
}
public boolean isRedirectToNonSecureConnection() {
return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION;
}
private CertificateCombinedException getCertificateCombinedException(Exception e) {
CertificateCombinedException result = null;
@@ -264,7 +304,8 @@ public class RemoteOperationResult implements Serializable {
}
Throwable cause = mException.getCause();
Throwable previousCause = null;
while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
while (cause != null && cause != previousCause &&
!(cause instanceof CertificateCombinedException)) {
previousCause = cause;
cause = cause.getCause();
}
@@ -314,15 +355,17 @@ public class RemoteOperationResult implements Serializable {
return "Unrecovered transport exception";
} else if (mException instanceof AccountNotFoundException) {
Account failedAccount = ((AccountNotFoundException)mException).getFailedAccount();
return mException.getMessage() + " (" + (failedAccount != null ? failedAccount.name : "NULL") + ")";
Account failedAccount =
((AccountNotFoundException)mException).getFailedAccount();
return mException.getMessage() + " (" +
(failedAccount != null ? failedAccount.name : "NULL") + ")";
} else if (mException instanceof AccountsException) {
return "Exception while using account";
} else if (mException instanceof JSONException) {
return "JSON exception";
return "JSON exception";
} else {
return "Unexpected exception";
}
@@ -348,13 +391,19 @@ public class RemoteOperationResult implements Serializable {
} else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
return "Authenticated with a different account than the one updating";
} else if (mCode == ResultCode.INVALID_CHARACTER_IN_NAME) {
return "The file name contains an forbidden character";
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
return "Local file does not exist";
}
return "Operation finished with HTTP status code " + mHttpCode + " (" + (isSuccess() ? "success" : "fail") + ")";
} else if (mCode == ResultCode.FILE_NOT_FOUND) {
return "Local file does not exist";
} else if (mCode == ResultCode.SYNC_CONFLICT) {
return "Synchronization conflict";
}
return "Operation finished with HTTP status code " + mHttpCode + " (" +
(isSuccess() ? "success" : "fail") + ")";
}
@@ -373,24 +422,32 @@ public class RemoteOperationResult implements Serializable {
public String getRedirectedLocation() {
return mRedirectedLocation;
}
public boolean isIdPRedirection() {
return (mRedirectedLocation != null &&
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
}
/**
* Checks if is a non https connection
*
* @return boolean true/false
*/
public boolean isNonSecureRedirection() {
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
/**
* Checks if is a non https connection
*
* @return boolean true/false
*/
public boolean isNonSecureRedirection() {
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
public String getAuthenticateHeader() {
return mAuthenticate;
return mAuthenticate;
}
public String getLastPermanentLocation() {
return mLastPermanentLocation;
}
public void setLastPermanentLocation(String lastPermanentLocation) {
mLastPermanentLocation = lastPermanentLocation;
}
}
@@ -32,8 +32,7 @@ public class Log_OC {
}
public static void i(String TAG, String message){
// Write the log message to the file
Log.i(TAG, message);
appendLog(TAG+" : "+ message);
}
@@ -61,7 +60,7 @@ public class Log_OC {
}
public static void w(String TAG, String message) {
Log.w(TAG,message);
Log.w(TAG, message);
appendLog(TAG+" : "+ message);
}
@@ -100,8 +99,16 @@ public class Log_OC {
}
} catch (IOException e) {
e.printStackTrace();
}
e.printStackTrace();
} finally {
if(mBuf != null) {
try {
mBuf.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
/**
@@ -160,10 +167,15 @@ public class Log_OC {
mBuf.newLine();
mBuf.write(text);
mBuf.newLine();
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Check if current log file size is bigger than the max file size defined
if (mLogFile.length() > MAX_FILE_SIZE) {