1
0
mirror of https://github.com/owncloud/android-library.git synced 2026-08-14 18:02:58 +00:00

apply codestyle everywhere

This commit is contained in:
Hannes Achleitner
2018-12-18 08:27:26 +01:00
parent 6d05856fb7
commit 40690df5fa
102 changed files with 2415 additions and 2472 deletions
@@ -11,7 +11,7 @@ import java.io.IOException;
/**
* Dynamic implementation of {@link OwnCloudClientManager}.
*
* <p>
* Wraps instances of {@link SingleSessionManager} and {@link SimpleFactoryManager} and delegates on one
* or the other depending on the known version of the server corresponding to the {@link OwnCloudAccount}
*
@@ -26,17 +26,17 @@ public class DynamicSessionManager implements OwnCloudClientManager {
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context)
throws AccountUtils.AccountNotFoundException,
OperationCanceledException, AuthenticatorException, IOException {
throws AccountUtils.AccountNotFoundException,
OperationCanceledException, AuthenticatorException, IOException {
OwnCloudVersion ownCloudVersion = null;
if (account.getSavedAccount() != null) {
ownCloudVersion = AccountUtils.getServerVersionForAccount(
account.getSavedAccount(), context
account.getSavedAccount(), context
);
}
if (ownCloudVersion != null && ownCloudVersion.isSessionMonitoringSupported()) {
if (ownCloudVersion != null && ownCloudVersion.isSessionMonitoringSupported()) {
return mSingleSessionManager.getClientFor(account, context);
} else {
return mSimpleFactoryManager.getClientFor(account, context);
@@ -24,14 +24,6 @@
package com.owncloud.android.lib.common;
import java.io.IOException;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
@@ -39,27 +31,33 @@ import android.accounts.OperationCanceledException;
import android.content.Context;
import android.net.Uri;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import java.io.IOException;
/**
* OwnCloud Account
*
*
* @author David A. Velasco
*/
public class OwnCloudAccount {
private Uri mBaseUri;
private Uri mBaseUri;
private OwnCloudCredentials mCredentials;
private String mDisplayName;
private String mSavedAccountName;
private Account mSavedAccount;
/**
* Constructor for already saved OC accounts.
*
* <p>
* Do not use for anonymous credentials.
*/
public OwnCloudAccount(Account savedAccount, Context context) throws AccountNotFoundException {
@@ -77,19 +75,18 @@ public class OwnCloudAccount {
AccountManager ama = AccountManager.get(context.getApplicationContext());
String baseUrl = ama.getUserData(mSavedAccount, AccountUtils.Constants.KEY_OC_BASE_URL);
if (baseUrl == null ) {
if (baseUrl == null) {
throw new AccountNotFoundException(mSavedAccount, "Account not found", null);
}
mBaseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, mSavedAccount));
mDisplayName = ama.getUserData(mSavedAccount, AccountUtils.Constants.KEY_DISPLAY_NAME);
}
/**
* Constructor for non yet saved OC accounts.
*
* @param baseUri URI to the OC server to get access to.
* @param credentials Credentials to authenticate in the server. NULL is valid for anonymous credentials.
* @param baseUri URI to the OC server to get access to.
* @param credentials Credentials to authenticate in the server. NULL is valid for anonymous credentials.
*/
public OwnCloudAccount(Uri baseUri, OwnCloudCredentials credentials) {
if (baseUri == null) {
@@ -99,14 +96,13 @@ public class OwnCloudAccount {
mSavedAccountName = null;
mBaseUri = baseUri;
mCredentials = credentials != null ?
credentials : OwnCloudCredentialsFactory.getAnonymousCredentials();
credentials : OwnCloudCredentialsFactory.getAnonymousCredentials();
String username = mCredentials.getUsername();
if (username != null) {
mSavedAccountName = AccountUtils.buildAccountName(mBaseUri, username);
}
}
/**
* Method for deferred load of account attributes from AccountManager
*
@@ -131,13 +127,13 @@ public class OwnCloudAccount {
public Uri getBaseUri() {
return mBaseUri;
}
public OwnCloudCredentials getCredentials() {
return mCredentials;
}
public String getName() {
return mSavedAccountName;
return mSavedAccountName;
}
public Account getSavedAccount() {
@@ -29,6 +29,7 @@ import android.accounts.AccountManager;
import android.accounts.AccountsException;
import android.net.Uri;
import at.bitfire.dav4android.exception.HttpException;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
@@ -40,16 +41,14 @@ import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.common.utils.RandomUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import okhttp3.Cookie;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import at.bitfire.dav4android.exception.HttpException;
import okhttp3.Cookie;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import static com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID;
public class OwnCloudClient extends HttpClient {
@@ -94,15 +93,6 @@ public class OwnCloudClient extends HttpClient {
clearCookies();
}
public void setCredentials(OwnCloudCredentials credentials) {
if (credentials != null) {
mCredentials = credentials;
mCredentials.applyTo(this);
} else {
clearCredentials();
}
}
public void clearCredentials() {
if (!(mCredentials instanceof OwnCloudAnonymousCredentials)) {
mCredentials = OwnCloudCredentialsFactory.getAnonymousCredentials();
@@ -114,7 +104,7 @@ public class OwnCloudClient extends HttpClient {
mCredentials.applyTo(this);
}
public int executeHttpMethod (HttpBaseMethod method) throws Exception {
public int executeHttpMethod(HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
int repeatCounter = 0;
int status;
@@ -125,7 +115,7 @@ public class OwnCloudClient extends HttpClient {
status = method.execute();
checkFirstRedirection(method);
if(mFollowRedirects && !isIdPRedirection()) {
if (mFollowRedirects && !isIdPRedirection()) {
status = followRedirection(method).getLastStatus();
}
@@ -140,12 +130,12 @@ public class OwnCloudClient extends HttpClient {
private void checkFirstRedirection(HttpBaseMethod method) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
if(location != null && !location.isEmpty()) {
if (location != null && !location.isEmpty()) {
mRedirectedLocation = location;
}
}
private int executeRedirectedHttpMethod (HttpBaseMethod method) throws Exception {
private int executeRedirectedHttpMethod(HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
int repeatCounter = 0;
int status;
@@ -217,9 +207,9 @@ public class OwnCloudClient extends HttpClient {
try {
status = executeRedirectedHttpMethod(method);
} catch (HttpException e) {
if(e.getMessage().contains(Integer.toString(HttpConstants.HTTP_MOVED_TEMPORARILY))) {
if (e.getMessage().contains(Integer.toString(HttpConstants.HTTP_MOVED_TEMPORARILY))) {
status = HttpConstants.HTTP_MOVED_TEMPORARILY;
} else {
} else {
throw e;
}
}
@@ -242,7 +232,9 @@ public class OwnCloudClient extends HttpClient {
public void exhaustResponse(InputStream responseBodyAsStream) {
if (responseBodyAsStream != null) {
try {
while (responseBodyAsStream.read(sExhaustBuffer) >= 0) ;
while (responseBodyAsStream.read(sExhaustBuffer) >= 0) {
;
}
responseBodyAsStream.close();
} catch (IOException io) {
@@ -252,7 +244,7 @@ public class OwnCloudClient extends HttpClient {
}
}
public Uri getBaseFilesWebDavUri(){
public Uri getBaseFilesWebDavUri() {
return Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0);
}
@@ -260,7 +252,7 @@ public class OwnCloudClient extends HttpClient {
return mCredentials instanceof OwnCloudAnonymousCredentials
? Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0)
: Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0 + AccountUtils.getUserId(
mAccount.getSavedAccount(), getContext()
mAccount.getSavedAccount(), getContext()
)
);
}
@@ -269,14 +261,18 @@ public class OwnCloudClient extends HttpClient {
return mCredentials instanceof OwnCloudAnonymousCredentials
? Uri.parse(mBaseUri + WEBDAV_UPLOADS_PATH_4_0)
: Uri.parse(mBaseUri + WEBDAV_UPLOADS_PATH_4_0 + AccountUtils.getUserId(
mAccount.getSavedAccount(), getContext()
mAccount.getSavedAccount(), getContext()
)
);
}
public Uri getBaseUri() {
return mBaseUri;
}
/**
* Sets the root URI to the ownCloud server.
*
* <p>
* Use with care.
*
* @param uri
@@ -288,14 +284,19 @@ public class OwnCloudClient extends HttpClient {
mBaseUri = uri;
}
public Uri getBaseUri() {
return mBaseUri;
}
public final OwnCloudCredentials getCredentials() {
return mCredentials;
}
public void setCredentials(OwnCloudCredentials credentials) {
if (credentials != null) {
mCredentials = credentials;
mCredentials.applyTo(this);
} else {
clearCredentials();
}
}
private void logCookie(Cookie cookie) {
Log_OC.d(TAG, "Cookie name: " + cookie.name());
Log_OC.d(TAG, " value: " + cookie.value());
@@ -348,27 +349,27 @@ public class OwnCloudClient extends HttpClient {
);
}
public void setOwnCloudVersion(OwnCloudVersion version) {
mVersion = version;
}
public OwnCloudVersion getOwnCloudVersion() {
return mVersion;
}
public void setAccount(OwnCloudAccount account) {
this.mAccount = account;
public void setOwnCloudVersion(OwnCloudVersion version) {
mVersion = version;
}
public OwnCloudAccount getAccount() {
return mAccount;
}
public void setAccount(OwnCloudAccount account) {
this.mAccount = account;
}
/**
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
*
* <p>
* Invalidates current credentials if the request failed as anauthorized.
*
* <p>
* Refresh current credentials if possible, and marks a retry.
*
* @param status
@@ -416,10 +417,9 @@ public class OwnCloudClient extends HttpClient {
* Determines if credentials should be invalidated according the to the HTTPS status
* of a network request just performed.
*
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
* cannot be invalidated with the given arguments.
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
* cannot be invalidated with the given arguments.
*/
private boolean shouldInvalidateAccountCredentials(int httpStatusCode) {
@@ -437,10 +437,10 @@ public class OwnCloudClient extends HttpClient {
/**
* Invalidates credentials stored for the given account in the system {@link AccountManager} and in
* current {@link OwnCloudClientManagerFactory#getDefaultSingleton()} instance.
*
* <p>
* {@link #shouldInvalidateAccountCredentials(int)} should be called first.
*
* @return 'True' if invalidation was successful, 'false' otherwise.
* @return 'True' if invalidation was successful, 'false' otherwise.
*/
private boolean invalidateAccountCredentials() {
AccountManager am = AccountManager.get(getContext());
@@ -462,6 +462,7 @@ public class OwnCloudClient extends HttpClient {
/**
* Check if the redirection is to an identity provider such as SAML or wayf
*
* @return true if the redirection location includes SAML or wayf, false otherwise
*/
private boolean isIdPRedirection() {
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -43,29 +43,28 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.io.IOException;
public class OwnCloudClientFactory {
final private static String TAG = OwnCloudClientFactory.class.getSimpleName();
/**
* Creates a OwnCloudClient setup for an ownCloud account
*
* <p>
* Do not call this method from the main thread.
*
* @param account The ownCloud account
* @param appContext Android application context
* @param currentActivity Caller {@link Activity}
* @return A OwnCloudClient object ready to be used
* @throws AuthenticatorException If the authenticator failed to get the authorization
* token for the account.
* @throws OperationCanceledException If the authenticator operation was cancelled while
* getting the authorization token for the account.
* @throws IOException If there was some I/O error while getting the
* authorization token for the account.
* @throws AccountNotFoundException If 'account' is unknown for the AccountManager
*
* @param account The ownCloud account
* @param appContext Android application context
* @param currentActivity Caller {@link Activity}
* @return A OwnCloudClient object ready to be used
* @throws AuthenticatorException If the authenticator failed to get the authorization
* token for the account.
* @throws OperationCanceledException If the authenticator operation was cancelled while
* getting the authorization token for the account.
* @throws IOException If there was some I/O error while getting the
* authorization token for the account.
* @throws AccountNotFoundException If 'account' is unknown for the AccountManager
*/
public static OwnCloudClient createOwnCloudClient (Account account, Context appContext,
Activity currentActivity)
public static OwnCloudClient createOwnCloudClient(Account account, Context appContext,
Activity currentActivity)
throws OperationCanceledException, AuthenticatorException, IOException,
AccountNotFoundException {
Uri baseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account));
@@ -79,57 +78,60 @@ public class OwnCloudClientFactory {
String username = AccountUtils.getUsernameForAccount(account);
if (isOauth2) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
null,
currentActivity,
null,
null);
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
null,
currentActivity,
null,
null);
Bundle result = future.getResult();
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) throw new AuthenticatorException("WTF!");
if (accessToken == null) {
throw new AuthenticatorException("WTF!");
}
client.setCredentials(
OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken)
OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken)
);
} else if (isSamlSso) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
null,
currentActivity,
null,
null);
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
null,
currentActivity,
null,
null);
Bundle result = future.getResult();
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) throw new AuthenticatorException("WTF!");
if (accessToken == null) {
throw new AuthenticatorException("WTF!");
}
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
null,
currentActivity,
null,
null
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
null,
currentActivity,
null,
null
);
Bundle result = future.getResult();
String password = result.getString(AccountManager.KEY_AUTHTOKEN);
OwnCloudVersion version = AccountUtils.getServerVersionForAccount(account, appContext);
client.setCredentials(
OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
(version != null && version.isPreemptiveAuthenticationPreferred())
)
OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
(version != null && version.isPreemptiveAuthenticationPreferred())
)
);
}
@@ -142,10 +144,10 @@ public class OwnCloudClientFactory {
/**
* Creates a OwnCloudClient to access a URL and sets the desired parameters for ownCloud
* client connections.
*
* @param uri URL to the ownCloud server; BASE ENTRY POINT, not WebDavPATH
* @param context Android context where the OwnCloudClient is being created.
* @return A OwnCloudClient object ready to be used
*
* @param uri URL to the ownCloud server; BASE ENTRY POINT, not WebDavPATH
* @param context Android context where the OwnCloudClient is being created.
* @return A OwnCloudClient object ready to be used
*/
public static OwnCloudClient createOwnCloudClient(Uri uri, Context context,
boolean followRedirects) {
@@ -154,7 +156,7 @@ public class OwnCloudClientFactory {
client.setFollowRedirects(followRedirects);
client.setContext(context);
return client;
}
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,17 +24,17 @@
package com.owncloud.android.lib.common;
import java.io.IOException;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import java.io.IOException;
/**
* Manager to create and reuse OwnCloudClient instances to access remote OC servers.
*
* Manager to create and reuse OwnCloudClient instances to access remote OC servers.
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
@@ -42,13 +42,13 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundExce
public interface OwnCloudClientManager {
OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws AccountNotFoundException,
OperationCanceledException, AuthenticatorException,
OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws AccountNotFoundException,
OperationCanceledException, AuthenticatorException,
IOException;
OwnCloudClient removeClientFor(OwnCloudAccount account);
void saveAllClients(Context context, String accountType)
throws AccountNotFoundException, AuthenticatorException,
IOException, OperationCanceledException;
throws AccountNotFoundException, AuthenticatorException,
IOException, OperationCanceledException;
}
@@ -25,16 +25,8 @@ package com.owncloud.android.lib.common;
public class OwnCloudClientManagerFactory {
public static enum Policy {
ALWAYS_NEW_CLIENT,
SINGLE_SESSION_PER_ACCOUNT,
SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING
}
private static Policy sDefaultPolicy = Policy.ALWAYS_NEW_CLIENT;
private static OwnCloudClientManager sDefaultSingleton;
private static String sUserAgent;
public static OwnCloudClientManager newDefaultOwnCloudClientManager() {
@@ -78,26 +70,32 @@ public class OwnCloudClientManagerFactory {
sDefaultPolicy = policy;
}
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
public static String getUserAgent() {
return sUserAgent;
}
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
private static boolean defaultSingletonMustBeUpdated(Policy policy) {
if (sDefaultSingleton == null) {
return false;
}
if (policy == Policy.ALWAYS_NEW_CLIENT &&
!(sDefaultSingleton instanceof SimpleFactoryManager)) {
!(sDefaultSingleton instanceof SimpleFactoryManager)) {
return true;
}
if (policy == Policy.SINGLE_SESSION_PER_ACCOUNT &&
!(sDefaultSingleton instanceof SingleSessionManager)) {
!(sDefaultSingleton instanceof SingleSessionManager)) {
return true;
}
return false;
}
public static enum Policy {
ALWAYS_NEW_CLIENT,
SINGLE_SESSION_PER_ACCOUNT,
SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING
}
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,13 +24,11 @@
package com.owncloud.android.lib.common;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
@@ -46,16 +44,16 @@ public class SimpleFactoryManager implements OwnCloudClientManager {
Log_OC.d(TAG, "getClientFor(OwnCloudAccount ... : ");
OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(
account.getBaseUri(),
context.getApplicationContext(),
true);
account.getBaseUri(),
context.getApplicationContext(),
true);
Log_OC.v(TAG, " new client {" +
(account.getName() != null ?
account.getName() :
AccountUtils.buildAccountName(account.getBaseUri(), "")
(account.getName() != null ?
account.getName() :
AccountUtils.buildAccountName(account.getBaseUri(), "")
) + ", " + client.hashCode() + "}");
) + ", " + client.hashCode() + "}");
if (account.getCredentials() == null) {
account.loadCredentials(context);
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -43,7 +43,7 @@ import java.util.concurrent.ConcurrentMap;
/**
* Implementation of {@link OwnCloudClientManager}
*
* <p>
* TODO check multithreading safety
*
* @author David A. Velasco
@@ -57,11 +57,10 @@ public class SingleSessionManager implements OwnCloudClientManager {
private static final String TAG = SingleSessionManager.class.getSimpleName();
private ConcurrentMap<String, OwnCloudClient> mClientsWithKnownUsername =
new ConcurrentHashMap<>();
new ConcurrentHashMap<>();
private ConcurrentMap<String, OwnCloudClient> mClientsWithUnknownUsername =
new ConcurrentHashMap<>();
new ConcurrentHashMap<>();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws OperationCanceledException,
@@ -77,9 +76,9 @@ public class SingleSessionManager implements OwnCloudClientManager {
OwnCloudClient client = null;
String accountName = account.getName();
String sessionName = account.getCredentials() == null ? "" :
AccountUtils.buildAccountName(
account.getBaseUri(),
account.getCredentials().getAuthToken());
AccountUtils.buildAccountName(
account.getBaseUri(),
account.getCredentials().getAuthToken());
if (accountName != null) {
client = mClientsWithKnownUsername.get(accountName);
@@ -110,9 +109,9 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (client == null) {
// no client to reuse - create a new one
client = OwnCloudClientFactory.createOwnCloudClient(
account.getBaseUri(),
context.getApplicationContext(),
true); // TODO remove dependency on OwnCloudClientFactory
account.getBaseUri(),
context.getApplicationContext(),
true); // TODO remove dependency on OwnCloudClientFactory
client.setAccount(account);
client.setContext(context);
client.setOwnCloudClientManager(this);
@@ -152,7 +151,6 @@ public class SingleSessionManager implements OwnCloudClientManager {
return client;
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -187,7 +185,6 @@ public class SingleSessionManager implements OwnCloudClientManager {
return null;
}
@Override
public void saveAllClients(Context context, String accountType) {
@@ -202,9 +199,9 @@ public class SingleSessionManager implements OwnCloudClientManager {
accountName = accountNames.next();
account = new Account(accountName, accountType);
AccountUtils.saveClient(
mClientsWithKnownUsername.get(accountName),
account,
context);
mClientsWithKnownUsername.get(accountName),
account,
context);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -33,17 +33,17 @@ public class AccountTypeUtils {
public static String getAuthTokenTypePass(String accountType) {
return accountType + ".password";
}
public static String getAuthTokenTypeAccessToken(String accountType) {
return accountType + ".oauth2.access_token";
return accountType + ".oauth2.access_token";
}
public static String getAuthTokenTypeRefreshToken(String accountType) {
return accountType + ".oauth2.refresh_token";
return accountType + ".oauth2.refresh_token";
}
public static String getAuthTokenTypeSamlSessionCookie(String accountType) {
return accountType + ".saml.web_sso.session_cookie";
return accountType + ".saml.web_sso.session_cookie";
}
}
@@ -1,23 +1,23 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
*
* 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,
*
* 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
* 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.
*
@@ -39,13 +39,12 @@ import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import okhttp3.Cookie;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Cookie;
public class AccountUtils {
private static final String TAG = AccountUtils.class.getSimpleName();
@@ -53,13 +52,13 @@ public class AccountUtils {
/**
* Constructs full url to host and webdav resource basing on host version
*
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
* @param account A stored ownCloud {@link Account}
* @return Full URL to WebDAV endpoint in the server corresponding to 'account'.
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
* @param account A stored ownCloud {@link Account}
* @return Full URL to WebDAV endpoint in the server corresponding to 'account'.
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
*/
public static String getWebDavUrlForAccount(Context context, Account account)
throws AccountNotFoundException {
throws AccountNotFoundException {
String webDavUrlForAccount = "";
try {
@@ -80,19 +79,20 @@ public class AccountUtils {
/**
* Extracts url server from the account
*
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
* @param account A stored ownCloud {@link Account}
* @return Full URL to the server corresponding to 'account', ending in the base path
* common to all API endpoints.
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
* @param account A stored ownCloud {@link Account}
* @return Full URL to the server corresponding to 'account', ending in the base path
* common to all API endpoints.
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
*/
public static String getBaseUrlForAccount(Context context, Account account)
throws AccountNotFoundException {
throws AccountNotFoundException {
AccountManager ama = AccountManager.get(context.getApplicationContext());
String baseurl = ama.getUserData(account, Constants.KEY_OC_BASE_URL);
if (baseurl == null)
if (baseurl == null) {
throw new AccountNotFoundException(account, "Account not found", null);
}
return baseurl;
}
@@ -116,8 +116,8 @@ public class AccountUtils {
/**
* Get the stored server version corresponding to an OC account.
*
* @param account An OC account
* @param context Application context
* @param account An OC account
* @param context Application context
* @return Version of the OC server, according to last check
*/
public static OwnCloudVersion getServerVersionForAccount(Account account, Context context) {
@@ -140,7 +140,7 @@ public class AccountUtils {
* @throws OperationCanceledException
*/
public static OwnCloudCredentials getCredentialsForAccount(Context context, Account account)
throws OperationCanceledException, AuthenticatorException, IOException {
throws OperationCanceledException, AuthenticatorException, IOException {
OwnCloudCredentials credentials;
AccountManager am = AccountManager.get(context);
@@ -158,30 +158,30 @@ public class AccountUtils {
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
false);
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
false);
credentials = OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken);
} else if (isSamlSso) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken);
} else {
String password = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
false);
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
false);
credentials = OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
version.isPreemptiveAuthenticationPreferred()
username,
password,
version.isPreemptiveAuthenticationPreferred()
);
}
@@ -190,8 +190,9 @@ public class AccountUtils {
/**
* Get the user id corresponding to an OC account.
*
* @param account ownCloud account
* @return user id
* @return user id
*/
public static String getUserId(Account account, Context context) {
AccountManager accountMgr = AccountManager.get(context);
@@ -232,7 +233,7 @@ public class AccountUtils {
String cookiesString = client.getCookiesString();
if (!"".equals(cookiesString)) {
ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString);
Log_OC.d(TAG, "Saving Cookies: "+ cookiesString );
Log_OC.d(TAG, "Saving Cookies: " + cookiesString);
}
}
}
@@ -240,9 +241,9 @@ public class AccountUtils {
/**
* Restore the client cookies persisted in an account stored in the system AccountManager.
*
* @param account Stored account.
* @param client Client to restore cookies in.
* @param context Android context used to access the system AccountManager.
* @param account Stored account.
* @param client Client to restore cookies in.
* @param context Android context used to access the system AccountManager.
*/
public static void restoreCookies(Account account, OwnCloudClient client, Context context) {
if (account == null) {
@@ -260,10 +261,12 @@ public class AccountUtils {
if (cookiesString != null) {
String[] rawCookies = cookiesString.split(";");
List<Cookie> cookieList = new ArrayList<>(rawCookies.length);
for(String rawCookie : rawCookies) {
for (String rawCookie : rawCookies) {
rawCookie = rawCookie.replace(" ", "");
final int equalPos = rawCookie.indexOf('=');
if (equalPos == -1) continue;
if (equalPos == -1) {
continue;
}
cookieList.add(new Cookie.Builder()
.name(rawCookie.substring(0, equalPos))
.value(rawCookie.substring(equalPos + 1))
@@ -26,7 +26,6 @@ package com.owncloud.android.lib.common.authentication;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import okhttp3.Credentials;
public class OwnCloudBasicCredentials implements OwnCloudCredentials {
@@ -39,7 +39,7 @@ public class OwnCloudCredentialsFactory {
}
public static OwnCloudCredentials newBasicCredentials(
String username, String password, boolean preemptiveMode
String username, String password, boolean preemptiveMode
) {
return new OwnCloudBasicCredentials(username, password, preemptiveMode);
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -32,14 +32,13 @@ public class BearerCredentials {
public static final int HASH_SEED = 17;
public static final int HASH_OFFSET = 37;
private String mAccessToken;
/**
* The constructor with the bearer token
*
* @param token The bearer token
* @param token The bearer token
*/
public BearerCredentials(String token) {
/*if (token == null) {
@@ -48,21 +47,19 @@ public class BearerCredentials {
mAccessToken = (token == null) ? "" : token;
}
/**
* Returns the access token
*
* @return The access token
* @return The access token
*/
public String getAccessToken() {
return mAccessToken;
}
/**
* Get this object string.
*
* @return The access token
* @return The access token
*/
public String toString() {
return mAccessToken;
@@ -74,19 +71,22 @@ public class BearerCredentials {
* @return The hash code of the access token
*/
public int hashCode() {
return HASH_SEED * HASH_OFFSET + mAccessToken.hashCode();
return HASH_SEED * HASH_OFFSET + mAccessToken.hashCode();
}
/**
* These credentials are assumed equal if accessToken is the same.
*
* @param o The other object to compare with.
*
* @return 'True' if the object is equivalent.
* @param o The other object to compare with.
* @return 'True' if the object is equivalent.
*/
public boolean equals(Object o) {
if (o == null) return false;
if (this == o) return true;
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (this.getClass().equals(o.getClass())) {
BearerCredentials that = (BearerCredentials) o;
if (mAccessToken.equals(that.mAccessToken)) {
@@ -26,34 +26,34 @@
package com.owncloud.android.lib.common.authentication.oauth;
/**
/**
* Constant values for OAuth 2 protocol.
*
* <p>
* Includes required and optional parameter NAMES used in the 'authorization code' grant type.
*/
public class OAuth2Constants {
/// Parameters to send to the Authorization Endpoint
public static final String KEY_RESPONSE_TYPE = "response_type";
public static final String KEY_REDIRECT_URI = "redirect_uri";
public static final String KEY_CLIENT_ID = "client_id";
public static final String KEY_SCOPE = "scope";
public static final String KEY_STATE = "state";
public static final String KEY_STATE = "state";
/// Additional parameters to send to the Token Endpoint
public static final String KEY_GRANT_TYPE = "grant_type";
public static final String KEY_CODE = "code";
// Used to get the Access Token using Refresh Token
public static final String OAUTH2_REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
/// Parameters received in an OK response from the Token Endpoint
public static final String KEY_ACCESS_TOKEN = "access_token";
public static final String KEY_TOKEN_TYPE = "token_type";
public static final String KEY_EXPIRES_IN = "expires_in";
public static final String KEY_REFRESH_TOKEN = "refresh_token";
/// Parameters in an ERROR response
public static final String KEY_ERROR = "error";
public static final String KEY_ERROR_DESCRIPTION = "error_description";
@@ -29,42 +29,37 @@ package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import org.json.JSONObject;
import java.net.URL;
import java.util.Map;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
private String mGrantType;
private String mCode;
private String mClientId;
private String mClientSecret;
private String mRedirectUri;
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
public OAuth2GetAccessTokenOperation(
String grantType,
String code,
String clientId,
String secretId,
String redirectUri,
String accessTokenEndpointPath
String grantType,
String code,
String clientId,
String secretId,
String redirectUri,
String accessTokenEndpointPath
) {
mClientId = clientId;
mClientSecret = secretId;
@@ -73,9 +68,9 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, S
mCode = code;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
;
mResponseParser = new OAuth2ResponseParser();
@@ -84,7 +79,7 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, S
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult<Map<String, String>> result = null;
try {
final RequestBody requestBody = new MultipartBody.Builder()
@@ -116,7 +111,7 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, S
if (response != null && response.length() > 0) {
JSONObject tokenJson = new JSONObject(response);
Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
result = new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR);
@@ -133,7 +128,7 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, S
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
}
return result;
}
@@ -31,36 +31,35 @@ public interface OAuth2Provider {
/**
* {@link OAuth2RequestBuilder} implementation for this provider.
*
* @return {@link OAuth2RequestBuilder} implementation.
* @return {@link OAuth2RequestBuilder} implementation.
*/
OAuth2RequestBuilder getOperationBuilder();
/**
* Set configuration of the client that will use this {@link OAuth2Provider}
* @param oAuth2ClientConfiguration Configuration of the client that will use this {@link OAuth2Provider}
*/
void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration);
/**
* Configuration of the client that is using this {@link OAuth2Provider}
* return Configuration of the client that is usinng this {@link OAuth2Provider}
*/
OAuth2ClientConfiguration getClientConfiguration();
/**
* Set base URI to authorization server.
* Set configuration of the client that will use this {@link OAuth2Provider}
*
* @param authorizationServerUri Set base URL to authorization server.
* @param oAuth2ClientConfiguration Configuration of the client that will use this {@link OAuth2Provider}
*/
void setAuthorizationServerUri(String authorizationServerUri);
void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration);
/**
* base URI to authorization server.
*
* @return Base URL to authorization server.
* @return Base URL to authorization server.
*/
String getAuthorizationServerUri();
/**
* Set base URI to authorization server.
*
* @param authorizationServerUri Set base URL to authorization server.
*/
void setAuthorizationServerUri(String authorizationServerUri);
}
@@ -26,7 +26,6 @@
package com.owncloud.android.lib.common.authentication.oauth;
import java.util.HashMap;
import java.util.Map;
@@ -36,20 +35,13 @@ public class OAuth2ProvidersRegistry {
private OAuth2Provider mDefaultProvider = null;
private OAuth2ProvidersRegistry () {
}
/**
* See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
*/
private static class LazyHolder {
private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry();
private OAuth2ProvidersRegistry() {
}
/**
* Singleton accesor.
*
* @return Singleton isntance of {@link OAuth2ProvidersRegistry}
* @return Singleton isntance of {@link OAuth2ProvidersRegistry}
*/
public static OAuth2ProvidersRegistry getInstance() {
return LazyHolder.INSTANCE;
@@ -58,8 +50,8 @@ public class OAuth2ProvidersRegistry {
/**
* Register an {@link OAuth2Provider} with the name passed as parameter.
*
* @param name Name to bind 'oAuthProvider' in the registry.
* @param oAuth2Provider An {@link OAuth2Provider} instance to keep in the registry.
* @param name Name to bind 'oAuthProvider' in the registry.
* @param oAuth2Provider An {@link OAuth2Provider} instance to keep in the registry.
* @throws IllegalArgumentException if 'name' or 'oAuthProvider' are null.
*/
public void registerProvider(String name, OAuth2Provider oAuth2Provider) {
@@ -89,7 +81,7 @@ public class OAuth2ProvidersRegistry {
/**
* Get default {@link OAuth2Provider}.
*
* @return Default provider, or NULL if there is no provider.
* @return Default provider, or NULL if there is no provider.
*/
public OAuth2Provider getProvider() {
return mDefaultProvider;
@@ -98,8 +90,8 @@ public class OAuth2ProvidersRegistry {
/**
* Get {@link OAuth2Provider} registered with the name passed as parameter.
*
* @param name Name used to register the desired {@link OAuth2Provider}
* @return {@link OAuth2Provider} registered with the name 'name'
* @param name Name used to register the desired {@link OAuth2Provider}
* @return {@link OAuth2Provider} registered with the name 'name'
*/
public OAuth2Provider getProvider(String name) {
return mProviders.get(name);
@@ -108,8 +100,8 @@ public class OAuth2ProvidersRegistry {
/**
* Sets the {@link OAuth2Provider} registered with the name passed as parameter as the default provider
*
* @param name Name used to register the {@link OAuth2Provider} to set as default.
* @return {@link OAuth2Provider} set as default, or NULL if no provider was registered with 'name'.
* @param name Name used to register the {@link OAuth2Provider} to set as default.
* @return {@link OAuth2Provider} set as default, or NULL if no provider was registered with 'name'.
*/
public OAuth2Provider setDefaultProvider(String name) {
OAuth2Provider toDefault = mProviders.get(name);
@@ -119,4 +111,11 @@ public class OAuth2ProvidersRegistry {
return toDefault;
}
/**
* See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
*/
private static class LazyHolder {
private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry();
}
}
@@ -31,7 +31,6 @@ import com.owncloud.android.lib.common.utils.Log_OC;
import java.util.HashMap;
import java.util.Map;
public class OAuth2QueryParser {
private static final String TAG = OAuth2QueryParser.class.getName();
@@ -1,59 +1,52 @@
/**
* ownCloud Android client application
*
* @author David González Verdugo
* @author Christian Schabesberger
*
* Copyright (C) 2018 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ownCloud Android client application
*
* @author David González Verdugo
* @author Christian Schabesberger
* <p>
* Copyright (C) 2018 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import org.json.JSONObject;
import java.net.URL;
import java.util.Map;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class OAuth2RefreshAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private static final String TAG = OAuth2RefreshAccessTokenOperation.class.getSimpleName();
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
private String mClientId;
private String mClientSecret;
private String mRefreshToken;
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
public OAuth2RefreshAccessTokenOperation(
String clientId,
String secretId,
@@ -30,10 +30,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
public interface OAuth2RequestBuilder {
enum OAuthRequest {
GET_AUTHORIZATION_CODE, CREATE_ACCESS_TOKEN, REFRESH_ACCESS_TOKEN
}
void setRequest(OAuthRequest operation);
void setGrantType(OAuth2GrantType grantType);
@@ -45,4 +41,8 @@ public interface OAuth2RequestBuilder {
RemoteOperation buildOperation();
String buildUri();
enum OAuthRequest {
GET_AUTHORIZATION_CODE, CREATE_ACCESS_TOKEN, REFRESH_ACCESS_TOKEN
}
}
@@ -1,27 +1,25 @@
/**
* ownCloud Android client application
*
* @author David A. Velasco
*
* Copyright (C) 2017 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ownCloud Android client application
*
* @author David A. Velasco
* <p>
* Copyright (C) 2017 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.common.authentication.oauth;
import org.json.JSONException;
import org.json.JSONObject;
@@ -35,40 +33,40 @@ class OAuth2ResponseParser {
if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_ACCESS_TOKEN));
getString(OAuth2Constants.KEY_ACCESS_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) {
resultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson.
getString(OAuth2Constants.KEY_TOKEN_TYPE));
getString(OAuth2Constants.KEY_TOKEN_TYPE));
}
if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) {
resultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson.
getString(OAuth2Constants.KEY_EXPIRES_IN));
getString(OAuth2Constants.KEY_EXPIRES_IN));
}
if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_REFRESH_TOKEN));
getString(OAuth2Constants.KEY_REFRESH_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) {
resultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson.
getString(OAuth2Constants.KEY_SCOPE));
getString(OAuth2Constants.KEY_SCOPE));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson.
getString(OAuth2Constants.KEY_ERROR));
getString(OAuth2Constants.KEY_ERROR));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson.
getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson.
getString(OAuth2Constants.KEY_ERROR_URI));
getString(OAuth2Constants.KEY_ERROR_URI));
}
if (tokenJson.has(OAuth2Constants.KEY_USER_ID)) { // not standard
resultTokenMap.put(OAuth2Constants.KEY_USER_ID, tokenJson.
getString(OAuth2Constants.KEY_USER_ID));
getString(OAuth2Constants.KEY_USER_ID));
}
return resultTokenMap;
@@ -46,19 +46,14 @@ public class OwnCloudOAuth2Provider implements OAuth2Provider {
return new OwnCloudOAuth2RequestBuilder(this);
}
@Override
public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) {
mClientConfiguration = oAuth2ClientConfiguration;
}
@Override
public OAuth2ClientConfiguration getClientConfiguration() {
return mClientConfiguration;
}
@Override
public void setAuthorizationServerUri(String authorizationServerUri) {
mAuthorizationServerUrl = authorizationServerUri;
public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) {
mClientConfiguration = oAuth2ClientConfiguration;
}
@Override
@@ -66,6 +61,11 @@ public class OwnCloudOAuth2Provider implements OAuth2Provider {
return mAuthorizationServerUrl;
}
@Override
public void setAuthorizationServerUri(String authorizationServerUri) {
mAuthorizationServerUrl = authorizationServerUri;
}
public String getAccessTokenEndpointPath() {
return mAccessTokenEndpointPath;
}
@@ -68,22 +68,22 @@ public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
if (mGrantType != OAuth2GrantType.AUTHORIZATION_CODE &&
mGrantType != OAuth2GrantType.REFRESH_TOKEN) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " and " +
OAuth2GrantType.REFRESH_TOKEN + " are supported"
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " and " +
OAuth2GrantType.REFRESH_TOKEN + " are supported"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
switch(mRequest) {
switch (mRequest) {
case CREATE_ACCESS_TOKEN:
return new OAuth2GetAccessTokenOperation(
mGrantType.getValue(),
mCode,
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
clientConfiguration.getRedirectUri(),
mOAuth2Provider.getAccessTokenEndpointPath()
mGrantType.getValue(),
mCode,
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
clientConfiguration.getRedirectUri(),
mOAuth2Provider.getAccessTokenEndpointPath()
);
case REFRESH_ACCESS_TOKEN:
@@ -95,7 +95,7 @@ public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
);
default:
throw new UnsupportedOperationException(
"Unsupported request"
"Unsupported request"
);
}
}
@@ -104,26 +104,26 @@ public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
public String buildUri() {
if (OAuth2GrantType.AUTHORIZATION_CODE != mGrantType) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported by this provider"
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported by this provider"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
Uri uri;
Uri.Builder uriBuilder;
switch(mRequest) {
switch (mRequest) {
case GET_AUTHORIZATION_CODE:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAuthorizationCodeEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
);
uri = uriBuilder.build();
@@ -134,13 +134,13 @@ public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAccessTokenEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
);
uri = uriBuilder.build();
@@ -148,7 +148,7 @@ public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
default:
throw new UnsupportedOperationException(
"Unsupported request"
"Unsupported request"
);
}
}
@@ -32,7 +32,15 @@ import com.owncloud.android.lib.common.http.interceptors.RequestHeaderIntercepto
import com.owncloud.android.lib.common.network.AdvancedX509TrustManager;
import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -41,18 +49,9 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
/**
* Client used to perform network operations
*
* @author David González Verdugo
*/
public class HttpClient {
@@ -63,21 +62,13 @@ public class HttpClient {
private static Context sContext;
private static HashMap<String, List<Cookie>> sCookieStore = new HashMap<>();
public static void setContext(Context context) {
sContext = context;
}
public Context getContext() {
return sContext;
}
public static OkHttpClient getOkHttpClient() {
if (sOkHttpClient == null) {
try {
final X509TrustManager trustManager = new AdvancedX509TrustManager(
NetworkUtils.getKnownServersStore(sContext));
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {trustManager}, null);
sslContext.init(null, new TrustManager[]{trustManager}, null);
// Automatic cookie handling, NOT PERSISTENT
CookieJar cookieJar = new CookieJar() {
@@ -109,8 +100,8 @@ public class HttpClient {
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
.hostnameVerifier((asdf, usdf) -> true)
.cookieJar(cookieJar);
// TODO: Not verifying the hostname against certificate. ask owncloud security human if this is ok.
//.hostnameVerifier(new BrowserCompatHostnameVerifier());
// TODO: Not verifying the hostname against certificate. ask owncloud security human if this is ok.
//.hostnameVerifier(new BrowserCompatHostnameVerifier());
sOkHttpClient = clientBuilder.build();
} catch (Exception e) {
@@ -130,6 +121,31 @@ public class HttpClient {
return sOkHttpInterceptor;
}
/**
* Add header that will be included for all the requests from now on
*
* @param headerName
* @param headerValue
*/
public static void addHeaderForAllRequests(String headerName, String headerValue) {
getOkHttpInterceptor()
.addRequestInterceptor(
new RequestHeaderInterceptor(headerName, headerValue)
);
}
public static void deleteHeaderForAllRequests(String headerName) {
getOkHttpInterceptor().deleteRequestHeaderInterceptor(headerName);
}
public Context getContext() {
return sContext;
}
public static void setContext(Context context) {
sContext = context;
}
public void disableAutomaticCookiesHandling() {
OkHttpClient.Builder clientBuilder = getOkHttpClient().newBuilder();
clientBuilder.cookieJar(new CookieJar() {
@@ -146,22 +162,6 @@ public class HttpClient {
sOkHttpClient = clientBuilder.build();
}
/**
* Add header that will be included for all the requests from now on
* @param headerName
* @param headerValue
*/
public static void addHeaderForAllRequests(String headerName, String headerValue) {
getOkHttpInterceptor()
.addRequestInterceptor(
new RequestHeaderInterceptor(headerName, headerValue)
);
}
public static void deleteHeaderForAllRequests(String headerName) {
getOkHttpInterceptor().deleteRequestHeaderInterceptor(headerName);
}
public List<Cookie> getCookiesFromUrl(HttpUrl httpUrl) {
return sCookieStore.get(httpUrl.host());
}
@@ -181,9 +181,13 @@ public class HttpConstants {
*************************************************** TIMEOUTS **********************************************
***********************************************************************************************************/
/** Default timeout for waiting data from the server */
/**
* Default timeout for waiting data from the server
*/
public static final int DEFAULT_DATA_TIMEOUT = 60000;
/** Default timeout for establishing a connection */
/**
* Default timeout for establishing a connection
*/
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
}
@@ -24,16 +24,17 @@
package com.owncloud.android.lib.common.http.interceptors;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Http interceptor to use multiple interceptors in the same {@link okhttp3.OkHttpClient} instance
*
* @author David González Verdugo
*/
public class HttpInterceptor implements Interceptor {
@@ -58,20 +59,12 @@ public class HttpInterceptor implements Interceptor {
return response;
}
public interface RequestInterceptor {
Request intercept(Request request) throws IOException;
}
public interface ResponseInterceptor {
Response intercept(Response response) throws IOException;
}
public HttpInterceptor addRequestInterceptor(RequestInterceptor requestInterceptor) {
mRequestInterceptors.add(requestInterceptor);
return this;
}
public HttpInterceptor addResponseInterceptor (ResponseInterceptor responseInterceptor) {
public HttpInterceptor addResponseInterceptor(ResponseInterceptor responseInterceptor) {
mResponseInterceptors.add(responseInterceptor);
return this;
}
@@ -106,4 +99,12 @@ public class HttpInterceptor implements Interceptor {
public ArrayList<ResponseInterceptor> getResponseInterceptors() {
return mResponseInterceptors;
}
public interface RequestInterceptor {
Request intercept(Request request) throws IOException;
}
public interface ResponseInterceptor {
Response intercept(Response response) throws IOException;
}
}
@@ -25,12 +25,6 @@
package com.owncloud.android.lib.common.http.methods;
import com.owncloud.android.lib.common.http.HttpClient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.HttpUrl;
@@ -39,6 +33,11 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Wrapper to perform http calls transparently by using:
* - OkHttp for non webdav methods
@@ -136,6 +135,12 @@ public abstract class HttpBaseMethod {
// Connection parameters
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
mOkHttpClient = mOkHttpClient.newBuilder()
.retryOnConnectionFailure(retryOnConnectionFailure)
.build();
}
public void setReadTimeout(long readTimeout, TimeUnit timeUnit) {
mOkHttpClient = mOkHttpClient.newBuilder()
.readTimeout(readTimeout, timeUnit)
@@ -154,12 +159,6 @@ public abstract class HttpBaseMethod {
.build();
}
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
mOkHttpClient = mOkHttpClient.newBuilder()
.retryOnConnectionFailure(retryOnConnectionFailure)
.build();
}
// Request
public void addRequestHeader(String name, String value) {
@@ -27,13 +27,12 @@ package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.HttpUrl;
/**
* OkHttp delete calls wrapper
*
* @author David González Verdugo
*/
public class DeleteMethod extends HttpMethod{
public class DeleteMethod extends HttpMethod {
public DeleteMethod(URL url) {
super(url);
@@ -27,10 +27,9 @@ package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.HttpUrl;
/**
* OkHttp get calls wrapper
*
* @author David González Verdugo
*/
public class GetMethod extends HttpMethod {
@@ -29,9 +29,6 @@ import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import java.io.IOException;
import java.net.URL;
import okhttp3.Call;
import okhttp3.HttpUrl;
/**
* Wrapper to perform OkHttp calls
*
@@ -27,15 +27,14 @@ package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.HttpUrl;
/**
* OkHttp post calls wrapper
*
* @author David González Verdugo
*/
public class PostMethod extends HttpMethod {
public PostMethod(URL url){
public PostMethod(URL url) {
super(url);
}
@@ -27,11 +27,9 @@ package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.HttpUrl;
public class PutMethod extends HttpMethod {
public class PutMethod extends HttpMethod{
public PutMethod(URL url){
public PutMethod(URL url) {
super(url);
}
@@ -24,12 +24,13 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import java.net.URL;
import kotlin.Unit;
import java.net.URL;
/**
* Copy calls wrapper
*
* @author Christian Schabesberger
* @author David González Verdugo
*/
@@ -24,23 +24,23 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import at.bitfire.dav4android.Constants;
import at.bitfire.dav4android.DavOCResource;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.dav4android.exception.RedirectException;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import okhttp3.HttpUrl;
import okhttp3.Protocol;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Wrapper to perform WebDAV (dav4android) calls
*
* @author David González Verdugo
*/
public abstract class DavMethod extends HttpBaseMethod {
@@ -124,6 +124,24 @@ public abstract class DavMethod extends HttpBaseMethod {
Constants.INSTANCE.getLog());
}
@Override
public void setUrl(HttpUrl url) {
super.setUrl(url);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public boolean getRetryOnConnectionFailure() {
return false; //TODO: implement me
}
//////////////////////////////
// Getter
//////////////////////////////
@Override
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
super.setRetryOnConnectionFailure(retryOnConnectionFailure);
@@ -133,24 +151,6 @@ public abstract class DavMethod extends HttpBaseMethod {
Constants.INSTANCE.getLog());
}
@Override
public void setUrl(HttpUrl url){
super.setUrl(url);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
//////////////////////////////
// Getter
//////////////////////////////
@Override
public boolean getRetryOnConnectionFailure() {
return false; //TODO: implement me
}
@Override
public boolean isAborted() {
return mDavResource.isCallAborted();
@@ -24,12 +24,13 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import java.net.URL;
import kotlin.Unit;
import java.net.URL;
/**
* MkCol calls wrapper
*
* @author Christian Schabesberger
* @author David González Verdugo
*/
@@ -25,13 +25,13 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import com.owncloud.android.lib.common.http.HttpConstants;
import kotlin.Unit;
import java.net.URL;
import kotlin.Unit;
/**
* Move calls wrapper
*
* @author Christian Schabesberger
* @author David González Verdugo
*/
@@ -24,18 +24,19 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.Response;
import at.bitfire.dav4android.exception.DavException;
import kotlin.Unit;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Propfind calls wrapper
*
* @author David González Verdugo
*/
public class PropfindMethod extends DavMethod {
@@ -57,7 +58,7 @@ public class PropfindMethod extends DavMethod {
}
@Override
public int onExecute() throws IOException, DavException{
public int onExecute() throws IOException, DavException {
mDavResource.propfind(mDepth, mPropertiesToRequest,
(Response response, Response.HrefRelation hrefRelation) -> {
switch (hrefRelation) {
@@ -24,23 +24,25 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import at.bitfire.dav4android.exception.HttpException;
import com.owncloud.android.lib.common.http.HttpConstants;
import kotlin.Unit;
import java.io.IOException;
import java.net.URL;
import at.bitfire.dav4android.exception.HttpException;
import kotlin.Unit;
/**
* Put calls wrapper
*
* @author David González Verdugo
*/
public class PutMethod extends DavMethod {
public PutMethod(URL url) {
super(url);
};
}
;
@Override
public int onExecute() throws IOException, HttpException {
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,6 +24,11 @@
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@@ -34,19 +39,11 @@ import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* @author David A. Velasco
*/
public class AdvancedX509TrustManager implements X509TrustManager {
private static final String TAG = AdvancedX509TrustManager.class.getSimpleName();
private X509TrustManager mStandardTrustManager = null;
@@ -54,27 +51,27 @@ public class AdvancedX509TrustManager implements X509TrustManager {
/**
* Constructor for AdvancedX509TrustManager
*
* @param knownServersKeyStore Local certificates store with server certificates explicitly trusted by the user.
* @throws CertStoreException When no default X509TrustManager instance was found in the system.
*
* @param knownServersKeyStore Local certificates store with server certificates explicitly trusted by the user.
* @throws CertStoreException When no default X509TrustManager instance was found in the system.
*/
public AdvancedX509TrustManager(KeyStore knownServersKeyStore)
throws NoSuchAlgorithmException, KeyStoreException, CertStoreException {
super();
TrustManagerFactory factory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init((KeyStore)null);
factory.init((KeyStore) null);
mStandardTrustManager = findX509TrustManager(factory);
mKnownServersKeyStore = knownServersKeyStore;
}
/**
* Locates the first X509TrustManager provided by a given TrustManagerFactory
* @param factory TrustManagerFactory to inspect in the search for a X509TrustManager
* @return The first X509TrustManager found in factory.
* @throws CertStoreException When no X509TrustManager instance was found in factory
*
* @param factory TrustManagerFactory to inspect in the search for a X509TrustManager
* @return The first X509TrustManager found in factory.
* @throws CertStoreException When no X509TrustManager instance was found in factory
*/
private X509TrustManager findX509TrustManager(TrustManagerFactory factory) throws CertStoreException {
TrustManager tms[] = factory.getTrustManagers();
@@ -85,36 +82,34 @@ public class AdvancedX509TrustManager implements X509TrustManager {
}
return null;
}
/**
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],
* String authType)
* String authType)
*/
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
mStandardTrustManager.checkClientTrusted(certificates, authType);
}
/**
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
* String authType)
* String authType)
*/
public void checkServerTrusted(X509Certificate[] certificates, String authType) {
if (!isKnownServer(certificates[0])) {
CertificateCombinedException result = new CertificateCombinedException(certificates[0]);
try {
certificates[0].checkValidity();
} catch (CertificateExpiredException c) {
result.setCertificateExpiredException(c);
} catch (CertificateNotYetValidException c) {
CertificateCombinedException result = new CertificateCombinedException(certificates[0]);
try {
certificates[0].checkValidity();
} catch (CertificateExpiredException c) {
result.setCertificateExpiredException(c);
} catch (CertificateNotYetValidException c) {
result.setCertificateNotYetException(c);
}
try {
mStandardTrustManager.checkServerTrusted(certificates, authType);
} catch (CertificateException c) {
}
try {
mStandardTrustManager.checkServerTrusted(certificates, authType);
} catch (CertificateException c) {
Throwable cause = c.getCause();
Throwable previousCause = null;
while (cause != null && cause != previousCause && !(cause instanceof CertPathValidatorException)) { // getCause() is not funny
@@ -122,19 +117,19 @@ public class AdvancedX509TrustManager implements X509TrustManager {
cause = cause.getCause();
}
if (cause != null && cause instanceof CertPathValidatorException) {
result.setCertPathValidatorException((CertPathValidatorException)cause);
result.setCertPathValidatorException((CertPathValidatorException) cause);
} else {
result.setOtherCertificateException(c);
result.setOtherCertificateException(c);
}
}
if (result.isException())
throw result;
}
if (result.isException()) {
throw result;
}
}
}
/**
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
@@ -142,7 +137,6 @@ public class AdvancedX509TrustManager implements X509TrustManager {
return mStandardTrustManager.getAcceptedIssuers();
}
public boolean isKnownServer(X509Certificate cert) {
try {
return (mKnownServersKeyStore.getCertificateAlias(cert) != null);
@@ -151,5 +145,5 @@ public class AdvancedX509TrustManager implements X509TrustManager {
return false;
}
}
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,36 +24,37 @@
package com.owncloud.android.lib.common.network;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLPeerUnverifiedException;
/**
* Exception joining all the problems that {@link AdvancedX509TrustManager} can find in
* a certificate chain for a server.
*
* <p>
* This was initially created as an extension of CertificateException, but some
* implementations of the SSL socket layer in existing devices are REPLACING the CertificateException
* instances thrown by {@link javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], String)}
* with SSLPeerUnverifiedException FORGETTING THE CAUSING EXCEPTION instead of wrapping it.
*
* Due to this, extending RuntimeException is necessary to get that the CertificateCombinedException
* with SSLPeerUnverifiedException FORGETTING THE CAUSING EXCEPTION instead of wrapping it.
* <p>
* Due to this, extending RuntimeException is necessary to get that the CertificateCombinedException
* instance reaches {@link AdvancedSslSocketFactory#verifyPeerIdentity}.
*
* <p>
* BE CAREFUL. As a RuntimeException extensions, Java compilers do not require to handle it
* in client methods. Be sure to use it only when you know exactly where it will go.
*
*
* @author David A. Velasco
*/
public class CertificateCombinedException extends RuntimeException {
/** Generated - to refresh every time the class changes */
/**
* Generated - to refresh every time the class changes
*/
private static final long serialVersionUID = -8875782030758554999L;
private X509Certificate mServerCert = null;
private String mHostInUrl;
@@ -62,7 +63,7 @@ public class CertificateCombinedException extends RuntimeException {
private CertPathValidatorException mCertPathValidatorException = null;
private CertificateException mOtherCertificateException = null;
private SSLPeerUnverifiedException mSslPeerUnverifiedException = null;
public CertificateCombinedException(X509Certificate x509Certificate) {
mServerCert = x509Certificate;
}
@@ -84,7 +85,7 @@ public class CertificateCombinedException extends RuntimeException {
}
public void setCertificateExpiredException(CertificateExpiredException c) {
mCertificateExpiredException = c;
mCertificateExpiredException = c;
}
public CertificateNotYetValidException getCertificateNotYetValidException() {
@@ -112,7 +113,7 @@ public class CertificateCombinedException extends RuntimeException {
}
public SSLPeerUnverifiedException getSslPeerUnverifiedException() {
return mSslPeerUnverifiedException ;
return mSslPeerUnverifiedException;
}
public void setSslPeerUnverifiedException(SSLPeerUnverifiedException s) {
@@ -27,6 +27,8 @@ package com.owncloud.android.lib.common.network;
import android.util.Log;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MediaType;
import okio.BufferedSink;
import java.io.File;
import java.io.IOException;
@@ -34,9 +36,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import okhttp3.MediaType;
import okio.BufferedSink;
/**
* A Request body that represents a file chunk and include information about the progress when uploading it
*
@@ -84,18 +83,19 @@ public class ChunkFromFileRequestBody extends FileRequestBody {
try {
mChannel.position(mOffset);
long size = mFile.length();
if (size == 0) size = -1;
if (size == 0) {
size = -1;
}
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
while (mChannel.position() < maxCount) {
Log_OC.d(TAG, "Sink buffer size: " + sink.buffer().size());
readCount = mChannel.read(mBuffer);
Log_OC.d(TAG, "Read " + readCount + " bytes from file channel to " + mBuffer.toString());
sink.buffer().write(mBuffer.array(), 0 ,readCount);
sink.buffer().write(mBuffer.array(), 0, readCount);
sink.flush();
@@ -118,14 +118,14 @@ public class ChunkFromFileRequestBody extends FileRequestBody {
} catch (Exception exception) {
Log.e(TAG, exception.toString());
// // any read problem will be handled as if the file is not there
// if (io instanceof FileNotFoundException) {
// throw io;
// } else {
// FileNotFoundException fnf = new FileNotFoundException("Exception reading source file");
// fnf.initCause(io);
// throw fnf;
// }
// // any read problem will be handled as if the file is not there
// if (io instanceof FileNotFoundException) {
// throw io;
// } else {
// FileNotFoundException fnf = new FileNotFoundException("Exception reading source file");
// fnf.initCause(io);
// throw fnf;
// }
}
}
@@ -26,7 +26,11 @@ package com.owncloud.android.lib.common.network;
import android.util.Log;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
import java.io.File;
import java.util.Collection;
@@ -34,12 +38,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
/**
* A Request body that represents a file and include information about the progress when uploading it
*
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,6 +24,11 @@
package com.owncloud.android.lib.common.network;
import android.content.Context;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -35,54 +40,50 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import android.content.Context;
import com.owncloud.android.lib.common.utils.Log_OC;
public class NetworkUtils {
final private static String TAG = NetworkUtils.class.getSimpleName();
/** Default timeout for waiting data from the server */
public static final int DEFAULT_DATA_TIMEOUT = 60000;
/** Default timeout for establishing a connection */
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
/** Standard name for protocol TLS version 1.2 in Java Secure Socket Extension (JSSE) API */
public static final String PROTOCOL_TLSv1_2 = "TLSv1.2";
/** Standard name for protocol TLS version 1.0 in JSSE API */
public static final String PROTOCOL_TLSv1_0 = "TLSv1";
/**
* Default timeout for waiting data from the server
*/
public static final int DEFAULT_DATA_TIMEOUT = 60000;
/**
* Default timeout for establishing a connection
*/
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
/**
* Standard name for protocol TLS version 1.2 in Java Secure Socket Extension (JSSE) API
*/
public static final String PROTOCOL_TLSv1_2 = "TLSv1.2";
/**
* Standard name for protocol TLS version 1.0 in JSSE API
*/
public static final String PROTOCOL_TLSv1_0 = "TLSv1";
final private static String TAG = NetworkUtils.class.getSimpleName();
private static X509HostnameVerifier mHostnameVerifier = null;
private static String LOCAL_TRUSTSTORE_FILENAME = "knownServers.bks";
private static String LOCAL_TRUSTSTORE_PASSWORD = "password";
private static KeyStore mKnownServersStore = null;
/**
* Returns the local store of reliable server certificates, explicitly accepted by the user.
*
* <p>
* Returns a KeyStore instance with empty content if the local store was never created.
*
* <p>
* Loads the store from the storage environment if needed.
*
* @param context Android context where the operation is being performed.
* @return KeyStore instance with explicitly-accepted server certificates.
* @throws KeyStoreException When the KeyStore instance could not be created.
* @throws IOException When an existing local trust store could not be loaded.
* @throws NoSuchAlgorithmException When the existing local trust store was saved with an unsupported algorithm.
* @throws CertificateException When an exception occurred while loading the certificates from the local
* trust store.
*
* @param context Android context where the operation is being performed.
* @return KeyStore instance with explicitly-accepted server certificates.
* @throws KeyStoreException When the KeyStore instance could not be created.
* @throws IOException When an existing local trust store could not be loaded.
* @throws NoSuchAlgorithmException When the existing local trust store was saved with an unsupported algorithm.
* @throws CertificateException When an exception occurred while loading the certificates from the local
* trust store.
*/
public static KeyStore getKnownServersStore(Context context)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
if (mKnownServersStore == null) {
//mKnownServersStore = KeyStore.getInstance("BKS");
mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -96,17 +97,16 @@ public class NetworkUtils {
in.close();
}
} else {
// next is necessary to initialize an empty KeyStore instance
mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
// next is necessary to initialize an empty KeyStore instance
mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
}
}
return mKnownServersStore;
}
public static void addCertToKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
public static void addCertToKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore knownServers = getKnownServersStore(context);
knownServers.setCertificateEntry(Integer.toString(cert.hashCode()), cert);
FileOutputStream fos = null;
@@ -118,13 +118,13 @@ public class NetworkUtils {
}
}
public static boolean isCertInKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore knownServers = getKnownServersStore(context);
Log_OC.d(TAG, "Certificate - HashCode: " + cert.hashCode() + " "
+ Boolean.toString(knownServers.isCertificateEntry(Integer.toString(cert.hashCode()))));
return knownServers.isCertificateEntry(Integer.toString(cert.hashCode()));
public static boolean isCertInKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore knownServers = getKnownServersStore(context);
Log_OC.d(TAG, "Certificate - HashCode: " + cert.hashCode() + " "
+ Boolean.toString(knownServers.isCertificateEntry(Integer.toString(cert.hashCode()))));
return knownServers.isCertificateEntry(Integer.toString(cert.hashCode()));
}
}
@@ -1,23 +1,23 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
*
* 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,
*
* 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
* 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.
*
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -26,11 +26,10 @@ package com.owncloud.android.lib.common.network;
import java.util.Collection;
public interface ProgressiveDataTransferer {
public void addDatatransferProgressListener (OnDatatransferProgressListener listener);
public void addDatatransferProgressListener(OnDatatransferProgressListener listener);
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
@@ -27,22 +27,19 @@
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.http.HttpConstants;
import java.util.Arrays;
/**
* Aggregate saving the list of URLs followed in a sequence of redirections during the exceution of a
* {@link RemoteOperation}, and the status codes corresponding to all
* of them.
*
* <p>
* 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.
*
* <p>
* If no redirection was followed, the last (and first) status code contained corresponds to the original URL in the
* request.
*/
@@ -59,9 +56,9 @@ public class RedirectionPath {
/**
* 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
* @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) {
@@ -75,7 +72,7 @@ public class RedirectionPath {
/**
* Adds a new location URL to the list of followed redirections.
*
* @param location URL extracted from a 'Location' header in a redirection.
* @param location URL extracted from a 'Location' header in a redirection.
*/
public void addLocation(String location) {
if (mLocations == null) {
@@ -86,11 +83,10 @@ public class RedirectionPath {
}
}
/**
* 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.
* @param status Status code from the response of another followed redirection.
*/
public void addStatus(int status) {
if (mLastStatus < mStatuses.length - 1) {
@@ -99,14 +95,14 @@ public class RedirectionPath {
}
/**
* @return Last status code saved.
* @return Last status code saved.
*/
public int getLastStatus() {
return mStatuses[mLastStatus];
}
/**
* @return Last location followed corresponding to a permanent redirection (status code 301).
* @return Last location followed corresponding to a permanent redirection (status code 301).
*/
public String getLastPermanentLocation() {
for (int i = mLastStatus; i >= 0; i--) {
@@ -118,11 +114,10 @@ public class RedirectionPath {
}
/**
* @return Count of locations.
* @return Count of locations.
*/
public int getRedirectionsCount() {
return mLastLocation + 1;
}
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,128 +24,122 @@
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import javax.net.ssl.SSLSocket;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLSocket;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* Enables the support of Server Name Indication if existing
* Enables the support of Server Name Indication if existing
* in the underlying network implementation.
*
* <p>
* Build as a singleton.
*
*
* @author David A. Velasco
*/
public class ServerNameIndicator {
private static final String TAG = ServerNameIndicator.class.getSimpleName();
private static final AtomicReference<ServerNameIndicator> mSingleInstance = new AtomicReference<ServerNameIndicator>();
private static final String METHOD_NAME = "setHostname";
private final WeakReference<Class<?>> mSSLSocketClassRef;
private final WeakReference<Method> mSetHostnameMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param sslSocketClass Underlying implementation class of {@link SSLSocket} used to connect with the server.
* @param setHostnameMethod Name of the method to call to enable the SNI support.
*/
private ServerNameIndicator(Class<?> sslSocketClass, Method setHostnameMethod) {
mSSLSocketClassRef = new WeakReference<Class<?>>(sslSocketClass);
mSetHostnameMethodRef = (setHostnameMethod == null) ? null : new WeakReference<Method>(setHostnameMethod);
}
/**
* Calls the {@code #setHostname(String)} method of the underlying implementation
* of {@link SSLSocket} if exists.
*
* Creates and initializes the single instance of the class when needed
*
* @param hostname The name of the server host of interest.
* @param sslSocket Client socket to connect with the server.
*/
public static void setServerNameIndication(String hostname, SSLSocket sslSocket) {
final Method setHostnameMethod = getMethod(sslSocket);
if (setHostnameMethod != null) {
try {
setHostnameMethod.invoke(sslSocket, hostname);
Log_OC.i(TAG, "SNI done, hostname: " + hostname);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (IllegalAccessException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (InvocationTargetException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
}
} else {
Log_OC.i(TAG, "SNI not supported");
}
}
/**
* Gets the method to invoke trying to minimize the effective
* application of reflection.
*
* @param sslSocket Instance of the SSL socket to use in connection with server.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method getMethod(SSLSocket sslSocket) {
final Class<?> sslSocketClass = sslSocket.getClass();
final ServerNameIndicator instance = mSingleInstance.get();
if (instance == null) {
return initFrom(sslSocketClass);
} else if (instance.mSSLSocketClassRef.get() != sslSocketClass) {
// the underlying class changed
return initFrom(sslSocketClass);
} else if (instance.mSetHostnameMethodRef == null) {
// SNI not supported
return null;
} else {
final Method cachedSetHostnameMethod = instance.mSetHostnameMethodRef.get();
return (cachedSetHostnameMethod == null) ? initFrom(sslSocketClass) : cachedSetHostnameMethod;
}
}
private static final String TAG = ServerNameIndicator.class.getSimpleName();
private static final AtomicReference<ServerNameIndicator> mSingleInstance = new AtomicReference<ServerNameIndicator>();
/**
* Singleton initializer.
*
* Uses reflection to extract and 'cache' the method to invoke to indicate the desited host name to the server side.
*
* @param sslSocketClass Underlying class providing the implementation of {@link SSLSocket}.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method initFrom(Class<?> sslSocketClass) {
private static final String METHOD_NAME = "setHostname";
private final WeakReference<Class<?>> mSSLSocketClassRef;
private final WeakReference<Method> mSetHostnameMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param sslSocketClass Underlying implementation class of {@link SSLSocket} used to connect with the server.
* @param setHostnameMethod Name of the method to call to enable the SNI support.
*/
private ServerNameIndicator(Class<?> sslSocketClass, Method setHostnameMethod) {
mSSLSocketClassRef = new WeakReference<Class<?>>(sslSocketClass);
mSetHostnameMethodRef = (setHostnameMethod == null) ? null : new WeakReference<Method>(setHostnameMethod);
}
/**
* Calls the {@code #setHostname(String)} method of the underlying implementation
* of {@link SSLSocket} if exists.
* <p>
* Creates and initializes the single instance of the class when needed
*
* @param hostname The name of the server host of interest.
* @param sslSocket Client socket to connect with the server.
*/
public static void setServerNameIndication(String hostname, SSLSocket sslSocket) {
final Method setHostnameMethod = getMethod(sslSocket);
if (setHostnameMethod != null) {
try {
setHostnameMethod.invoke(sslSocket, hostname);
Log_OC.i(TAG, "SNI done, hostname: " + hostname);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (IllegalAccessException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (InvocationTargetException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
}
} else {
Log_OC.i(TAG, "SNI not supported");
}
}
/**
* Gets the method to invoke trying to minimize the effective
* application of reflection.
*
* @param sslSocket Instance of the SSL socket to use in connection with server.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method getMethod(SSLSocket sslSocket) {
final Class<?> sslSocketClass = sslSocket.getClass();
final ServerNameIndicator instance = mSingleInstance.get();
if (instance == null) {
return initFrom(sslSocketClass);
} else if (instance.mSSLSocketClassRef.get() != sslSocketClass) {
// the underlying class changed
return initFrom(sslSocketClass);
} else if (instance.mSetHostnameMethodRef == null) {
// SNI not supported
return null;
} else {
final Method cachedSetHostnameMethod = instance.mSetHostnameMethodRef.get();
return (cachedSetHostnameMethod == null) ? initFrom(sslSocketClass) : cachedSetHostnameMethod;
}
}
/**
* Singleton initializer.
* <p>
* Uses reflection to extract and 'cache' the method to invoke to indicate the desited host name to the server side.
*
* @param sslSocketClass Underlying class providing the implementation of {@link SSLSocket}.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method initFrom(Class<?> sslSocketClass) {
Log_OC.i(TAG, "SSLSocket implementation: " + sslSocketClass.getCanonicalName());
Method setHostnameMethod = null;
try {
setHostnameMethod = sslSocketClass.getMethod(METHOD_NAME, String.class);
} catch (SecurityException e) {
Log_OC.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e);
} catch (NoSuchMethodException e) {
Log_OC.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported");
}
mSingleInstance.set(new ServerNameIndicator(sslSocketClass, setHostnameMethod));
return setHostnameMethod;
}
Method setHostnameMethod = null;
try {
setHostnameMethod = sslSocketClass.getMethod(METHOD_NAME, String.class);
} catch (SecurityException e) {
Log_OC.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e);
} catch (NoSuchMethodException e) {
Log_OC.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported");
}
mSingleInstance.set(new ServerNameIndicator(sslSocketClass, setHostnameMethod));
return setHostnameMethod;
}
}
@@ -1,23 +1,23 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
*
* 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,
*
* 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
* 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.
*
@@ -25,64 +25,64 @@
package com.owncloud.android.lib.common.network;
import android.net.Uri;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.net.Uri;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
public class WebdavUtils {
public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
"dd.MM.yyyy hh:mm");
private static final SimpleDateFormat DATETIME_FORMATS[] = {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US),
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.US)
};
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US),
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.US)
};
public static Date parseResponseDate(String date) {
Date returnDate = null;
SimpleDateFormat format = null;
for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
try {
format = DATETIME_FORMATS[i];
synchronized(format) {
returnDate = format.parse(date);
}
format = DATETIME_FORMATS[i];
synchronized (format) {
returnDate = format.parse(date);
}
return returnDate;
} catch (ParseException e) {
// this is not the format
// this is not the format
}
}
return null;
}
/**
* Encodes a path according to URI RFC 2396.
*
* Encodes a path according to URI RFC 2396.
* <p>
* If the received path doesn't start with "/", the method adds it.
*
* @param remoteFilePath Path
* @return Encoded path according to RFC 2396, always starting with "/"
*
* @param remoteFilePath Path
* @return Encoded path according to RFC 2396, always starting with "/"
*/
public static String encodePath(String remoteFilePath) {
String encodedPath = Uri.encode(remoteFilePath, "/");
if (!encodedPath.startsWith("/"))
if (!encodedPath.startsWith("/")) {
encodedPath = "/" + encodedPath;
}
return encodedPath;
}
/**
*
* @param rawEtag
* @return
*/
@@ -100,7 +100,6 @@ public class WebdavUtils {
}
/**
*
* @param httpBaseMethod from which to get the etag
* @return etag from response
*/
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -32,18 +32,17 @@ import java.lang.reflect.Method;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicReference;
/**
* Enforces, if possible, a write timeout for a socket.
*
* <p>
* Built as a singleton.
*
* <p>
* Tries to hit something like this:
* https://android.googlesource.com/platform/external/conscrypt/+/lollipop-release/src/main/java/org/conscrypt/OpenSSLSocketImpl.java#1005
*
* <p>
* Minimizes the chances of getting stalled in PUT/POST request if the network interface is lost while
* writing the entity into the outwards sockect.
*
* <p>
* It happens. See https://github.com/owncloud/android/issues/1684#issuecomment-295306015
*
* @author David A. Velasco
@@ -56,36 +55,33 @@ public class WriteTimeoutEnforcer {
private static final String METHOD_NAME = "setSoWriteTimeout";
private final WeakReference<Class<?>> mSocketClassRef;
private final WeakReference<Method> mSetSoWriteTimeoutMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param socketClass Underlying implementation class of {@link Socket} used to connect
* with the server.
* @param setSoWriteTimeoutMethod Name of the method to call to set a write timeout in the socket.
* @param socketClass Underlying implementation class of {@link Socket} used to connect
* with the server.
* @param setSoWriteTimeoutMethod Name of the method to call to set a write timeout in the socket.
*/
private WriteTimeoutEnforcer(Class<?> socketClass, Method setSoWriteTimeoutMethod) {
mSocketClassRef = new WeakReference<Class<?>>(socketClass);
mSetSoWriteTimeoutMethodRef =
(setSoWriteTimeoutMethod == null) ?
null :
new WeakReference<>(setSoWriteTimeoutMethod)
(setSoWriteTimeoutMethod == null) ?
null :
new WeakReference<>(setSoWriteTimeoutMethod)
;
}
/**
* Calls the {@code #setSoWrite(int)} method of the underlying implementation
* of {@link Socket} if exists.
* <p>
* Creates and initializes the single instance of the class when needed
*
* @param writeTimeoutMilliseconds Write timeout to set, in milliseconds.
* @param socket Client socket to connect with the server.
* @param writeTimeoutMilliseconds Write timeout to set, in milliseconds.
* @param socket Client socket to connect with the server.
*/
public static void setSoWriteTimeout(int writeTimeoutMilliseconds, Socket socket) {
final Method setSoWriteTimeoutMethod = getMethod(socket);
@@ -93,9 +89,9 @@ public class WriteTimeoutEnforcer {
try {
setSoWriteTimeoutMethod.invoke(socket, writeTimeoutMilliseconds);
Log_OC.i(
TAG,
"Write timeout set in socket, writeTimeoutMilliseconds: "
+ writeTimeoutMilliseconds
TAG,
"Write timeout set in socket, writeTimeoutMilliseconds: "
+ writeTimeoutMilliseconds
);
} catch (IllegalArgumentException e) {
@@ -112,13 +108,12 @@ public class WriteTimeoutEnforcer {
}
}
/**
* Gets the method to invoke trying to minimize the cost of reflection reusing objects cached
* in static members.
*
* @param socket Instance of the socket to use in connection with server.
* @return Method to call to set a write timeout in the socket.
* @param socket Instance of the socket to use in connection with server.
* @return Method to call to set a write timeout in the socket.
*/
private static Method getMethod(Socket socket) {
final Class<?> socketClass = socket.getClass();
@@ -137,20 +132,19 @@ public class WriteTimeoutEnforcer {
} else {
final Method cachedSetSoWriteTimeoutMethod = instance.mSetSoWriteTimeoutMethodRef.get();
return (cachedSetSoWriteTimeoutMethod == null) ?
initFrom(socketClass) :
cachedSetSoWriteTimeoutMethod
;
initFrom(socketClass) :
cachedSetSoWriteTimeoutMethod
;
}
}
/**
* Singleton initializer.
*
* <p>
* Uses reflection to extract and 'cache' the method to invoke to set a write timouet in a socket.
*
* @param socketClass Underlying class providing the implementation of {@link Socket}.
* @return Method to call to set a write timeout in the socket.
* @param socketClass Underlying class providing the implementation of {@link Socket}.
* @return Method to call to set a write timeout in the socket.
*/
private static Method initFrom(Class<?> socketClass) {
Log_OC.i(TAG, "Socket implementation: " + socketClass.getCanonicalName());
@@ -162,8 +156,8 @@ public class WriteTimeoutEnforcer {
} catch (NoSuchMethodException e) {
Log_OC.i(
TAG,
"Could not find (SocketImpl)#setSoWriteTimeout(int) method - write timeout not supported"
TAG,
"Could not find (SocketImpl)#setSoWriteTimeout(int) method - write timeout not supported"
);
}
mSingleInstance.set(new WriteTimeoutEnforcer(socketClass, setSoWriteTimeoutMethod));
@@ -34,105 +34,110 @@ import java.io.InputStream;
/**
* Parser for server exceptions
*
* @author davidgonzalez
*/
public class ErrorMessageParser {
// No namespaces
private static final String ns = null;
// 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_MESSAGE = "s:message";
// Nodes for XML Parser
private static final String NODE_ERROR = "d:error";
private static final String NODE_MESSAGE = "s:message";
/**
* Parse exception response
* @param is
* @return errorMessage for an exception
* @throws XmlPullParserException
* @throws IOException
*/
public String parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
String errorMessage = "";
/**
* Parse exception response
*
* @param is
* @return errorMessage for an exception
* @throws XmlPullParserException
* @throws IOException
*/
public String parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
String errorMessage = "";
try {
// XMLPullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
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();
errorMessage = readError(parser);
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);
parser.nextTag();
errorMessage = readError(parser);
} finally {
is.close();
}
return errorMessage;
}
} finally {
is.close();
}
return errorMessage;
}
/**
* Parse OCS node
* @param parser
* @return reason for exception
* @throws XmlPullParserException
* @throws IOException
*/
private String readError (XmlPullParser parser) throws XmlPullParserException, IOException {
String errorMessage = "";
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_MESSAGE
if (name.equalsIgnoreCase(NODE_MESSAGE)) {
errorMessage = readText(parser);
} else {
skip(parser);
}
}
return errorMessage;
}
/**
* Parse OCS node
*
* @param parser
* @return reason for exception
* @throws XmlPullParserException
* @throws IOException
*/
private String readError(XmlPullParser parser) throws XmlPullParserException, IOException {
String errorMessage = "";
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_MESSAGE
if (name.equalsIgnoreCase(NODE_MESSAGE)) {
errorMessage = readText(parser);
} else {
skip(parser);
}
}
return errorMessage;
}
/**
* 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;
}
}
}
/**
* 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;
}
/**
* 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;
}
}
@@ -35,110 +35,116 @@ 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";
private static final String EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException";
// No namespaces
private static final String ns = null;
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";
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,
* 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);
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);
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;
}
} 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);
}
/**
* 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);
}
}
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;
}
}
}
/**
* 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;
}
/**
* 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;
}
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -24,9 +24,8 @@
package com.owncloud.android.lib.common.operations;
public interface OnRemoteOperationListener {
void onRemoteOperationFinish(RemoteOperation caller, RemoteOperationResult result);
void onRemoteOperationFinish(RemoteOperation caller, RemoteOperationResult result);
}
@@ -1,22 +1,22 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
*
* 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,
*
* 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
* 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.
*
@@ -12,25 +12,21 @@ import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.OkHttpClient;
import java.io.IOException;
import okhttp3.OkHttpClient;
public abstract class RemoteOperation<T extends Object> implements Runnable {
private static final String TAG = RemoteOperation.class.getSimpleName();
/**
* OCS API header name
*/
public static final String OCS_API_HEADER = "OCS-APIREQUEST";
/**
* OCS API header value
*/
public static final String OCS_API_HEADER_VALUE = "true";
private static final String TAG = RemoteOperation.class.getSimpleName();
/**
* ownCloud account in the remote ownCloud server to operate
*/
@@ -61,10 +57,9 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
*/
protected Handler mListenerHandler = null;
/**
* Asynchronously executes the remote operation
*
* <p>
* This method should be used whenever an ownCloud account is available,
* instead of {@link #execute(OwnCloudClient, OnRemoteOperationListener, Handler))}.
*
@@ -79,12 +74,14 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
public Thread execute(Account account, Context context,
OnRemoteOperationListener listener, Handler listenerHandler) {
if (account == null)
if (account == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL Account");
if (context == null)
}
if (context == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL Context");
}
// mAccount and mContext in the runnerThread to create below
mAccount = account;
mContext = context.getApplicationContext();
@@ -99,7 +96,6 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
return runnerThread;
}
/**
* Asynchronously executes the remote operation
*
@@ -168,9 +164,9 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
/**
* Synchronously executes the remote operation on the received ownCloud account.
*
* <p>
* Do not call this method from the main thread.
*
* <p>
* This method should be used whenever an ownCloud account is available, instead of
* {@link #execute(OwnCloudClient)}.
*
@@ -180,22 +176,23 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
* @return Result of the operation.
*/
public RemoteOperationResult<T> execute(Account account, Context context) {
if (account == null)
if (account == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Account");
if (context == null)
}
if (context == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Context");
}
mAccount = account;
mContext = context.getApplicationContext();
return runOperation();
}
/**
* Synchronously executes the remote operation
*
* <p>
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
@@ -203,9 +200,10 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
* @return Result of the operation.
*/
public RemoteOperationResult<T> execute(OwnCloudClient client) {
if (client == null)
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
}
mClient = client;
if (client.getAccount() != null) {
mAccount = client.getAccount().getSavedAccount();
@@ -217,7 +215,7 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
/**
* Synchronously executes the remote operation
*
* <p>
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
@@ -225,9 +223,10 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
* @return Result of the operation.
*/
public RemoteOperationResult<T> execute(OkHttpClient client, Context context) {
if (client == null)
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
}
mHttpClient = client;
mContext = context;
@@ -236,12 +235,12 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
/**
* Run operation for asynchronous or synchronous 'onExecute' method.
*
* <p>
* Considers and performs silent refresh of account credentials if possible, and if
* {@link RemoteOperation#setSilentRefreshOfAccountCredentials(boolean)} was called with
* parameter 'true' before the execution.
*
* @return Remote operation result
* @return Remote operation result
*/
private RemoteOperationResult<T> runOperation() {
@@ -27,14 +27,18 @@ package com.owncloud.android.lib.common.operations;
import android.accounts.Account;
import android.accounts.AccountsException;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.Headers;
import org.json.JSONException;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -48,13 +52,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import okhttp3.Headers;
public class RemoteOperationResult<T extends Object>
implements Serializable {
@@ -64,61 +61,6 @@ public class RemoteOperationResult<T extends Object>
private static final long serialVersionUID = 4968939884332372230L;
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,
SSL_ERROR,
SSL_RECOVERABLE_PEER_UNVERIFIED,
BAD_OC_VERSION,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
INVALID_OVERWRITE,
CONFLICT,
OAUTH2_ERROR,
SYNC_CONFLICT,
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,
ACCOUNT_NOT_THE_SAME,
INVALID_CHARACTER_IN_NAME,
SHARE_NOT_FOUND,
LOCAL_STORAGE_NOT_REMOVED,
FORBIDDEN,
SHARE_FORBIDDEN,
SPECIFIC_FORBIDDEN,
OK_REDIRECT_TO_NON_SECURE_CONNECTION,
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,
DELAYED_FOR_WIFI,
LOCAL_FILE_NOT_FOUND,
SERVICE_UNAVAILABLE,
SPECIFIC_SERVICE_UNAVAILABLE,
SPECIFIC_UNSUPPORTED_MEDIA_TYPE,
SPECIFIC_METHOD_NOT_ALLOWED
}
private boolean mSuccess = false;
private int mHttpCode = -1;
private String mHttpPhrase = null;
@@ -128,10 +70,9 @@ public class RemoteOperationResult<T extends Object>
private ArrayList<String> mAuthenticate = new ArrayList<>();
private String mLastPermanentLocation = null;
private T mData = null;
/**
* Public constructor from result code.
*
* <p>
* To be used when the caller takes the responsibility of interpreting the result of a {@link RemoteOperation}
*
* @param code {@link ResultCode} decided by the caller.
@@ -146,6 +87,7 @@ public class RemoteOperationResult<T extends Object>
/**
* Create a new RemoteOperationResult based on the result given by a previous one.
* It does not copy the data.
*
* @param prevRemoteOperation
*/
public RemoteOperationResult(RemoteOperationResult prevRemoteOperation) {
@@ -161,9 +103,9 @@ public class RemoteOperationResult<T extends Object>
/**
* Public constructor from exception.
*
* <p>
* To be used when an exception prevented the end of the {@link RemoteOperation}.
*
* <p>
* Determines a {@link ResultCode} depending on the type of the exception.
*
* @param e Exception that interrupted the {@link RemoteOperation}
@@ -193,7 +135,7 @@ public class RemoteOperationResult<T extends Object>
mCode = ResultCode.ACCOUNT_EXCEPTION;
} else if (e instanceof SSLException || e instanceof RuntimeException) {
if(e instanceof SSLPeerUnverifiedException) {
if (e instanceof SSLPeerUnverifiedException) {
mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
} else {
CertificateCombinedException se = getCertificateCombinedException(e);
@@ -220,9 +162,9 @@ public class RemoteOperationResult<T extends Object>
/**
* Public constructor from separate elements of an HTTP or DAV response.
*
* <p>
* To be used when the result needs to be interpreted from the response of an HTTP/DAV method.
*
* <p>
* Determines a {@link ResultCode} from the already executed method received as a parameter. Generally,
* will depend on the HTTP code and HTTP response headers received. In some cases will inspect also the
* response body
@@ -285,44 +227,18 @@ public class RemoteOperationResult<T extends Object>
}
}
/**
* Parse the error message included in the body response, if any, and set the specific result
* code
*
* @param bodyResponse okHttp response body
* @param resultCode our own custom result code
* @throws IOException
*/
private void parseErrorMessageAndSetCode(String bodyResponse, ResultCode resultCode) {
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
ErrorMessageParser xmlParser = new ErrorMessageParser();
try {
String errorMessage = xmlParser.parseXMLResponse(is);
if (errorMessage != "" && errorMessage != null) {
mCode = resultCode;
mHttpPhrase = errorMessage;
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
}
/**
* Public constructor from separate elements of an HTTP or DAV response.
*
* <p>
* To be used when the result needs to be interpreted from HTTP response elements that could come from
* different requests (WARNING: black magic, try to avoid).
*
*
* <p>
* <p>
* Determines a {@link ResultCode} depending on the HTTP code and HTTP response headers received.
*
* @param httpCode HTTP status code returned by an HTTP/DAV method.
* @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method
* @param headers HTTP response header returned by an HTTP/DAV method
* @param httpCode HTTP status code returned by an HTTP/DAV method.
* @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method
* @param headers HTTP response header returned by an HTTP/DAV method
*/
public RemoteOperationResult(int httpCode, String httpPhrase, Headers headers) {
this(httpCode, httpPhrase);
@@ -345,7 +261,7 @@ public class RemoteOperationResult<T extends Object>
/**
* Private constructor for results built interpreting a HTTP or DAV response.
*
* <p>
* Determines a {@link ResultCode} depending of the type of the exception.
*
* @param httpCode HTTP status code returned by the HTTP/DAV method.
@@ -389,11 +305,40 @@ public class RemoteOperationResult<T extends Object>
}
}
/**
* Parse the error message included in the body response, if any, and set the specific result
* code
*
* @param bodyResponse okHttp response body
* @param resultCode our own custom result code
* @throws IOException
*/
private void parseErrorMessageAndSetCode(String bodyResponse, ResultCode resultCode) {
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
ErrorMessageParser xmlParser = new ErrorMessageParser();
try {
String errorMessage = xmlParser.parseXMLResponse(is);
if (errorMessage != "" && errorMessage != null) {
mCode = resultCode;
mHttpPhrase = errorMessage;
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
}
public boolean isSuccess() {
return mSuccess;
}
public void setSuccess(boolean success) {
this.mSuccess = success;
}
public boolean isCancelled() {
return mCode == ResultCode.CANCELLED;
}
@@ -459,10 +404,11 @@ public class RemoteOperationResult<T extends Object>
return "Unknown host exception";
} else if (mException instanceof CertificateCombinedException) {
if (((CertificateCombinedException) mException).isRecoverable())
if (((CertificateCombinedException) mException).isRecoverable()) {
return "SSL recoverable exception";
else
} else {
return "SSL exception";
}
} else if (mException instanceof SSLException) {
return "SSL exception";
@@ -572,15 +518,65 @@ public class RemoteOperationResult<T extends Object>
mLastPermanentLocation = lastPermanentLocation;
}
public void setSuccess(boolean success) {
this.mSuccess = success;
public T getData() {
return mData;
}
public void setData(T data) {
mData = data;
}
public T getData() {
return mData;
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,
SSL_ERROR,
SSL_RECOVERABLE_PEER_UNVERIFIED,
BAD_OC_VERSION,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
INVALID_OVERWRITE,
CONFLICT,
OAUTH2_ERROR,
SYNC_CONFLICT,
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,
ACCOUNT_NOT_THE_SAME,
INVALID_CHARACTER_IN_NAME,
SHARE_NOT_FOUND,
LOCAL_STORAGE_NOT_REMOVED,
FORBIDDEN,
SHARE_FORBIDDEN,
SPECIFIC_FORBIDDEN,
OK_REDIRECT_TO_NON_SECURE_CONNECTION,
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,
DELAYED_FOR_WIFI,
LOCAL_FILE_NOT_FOUND,
SERVICE_UNAVAILABLE,
SPECIFIC_SERVICE_UNAVAILABLE,
SPECIFIC_UNSUPPORTED_MEDIA_TYPE,
SPECIFIC_METHOD_NOT_ALLOWED
}
}
@@ -39,7 +39,6 @@ public class RandomUtils {
/**
* @param length the number of random chars to be generated
*
* @return String containing random chars
*/
public static String generateRandomString(int length) {
@@ -59,7 +58,7 @@ public class RandomUtils {
*/
public static int generateRandomInteger(int min, int max) {
Random r = new Random();
return r.nextInt(max-min) + min;
return r.nextInt(max - min) + min;
}
/**