1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-08 00:16:09 +00:00

Merge pull request #192 from owncloud/replace_network_library

Replace network library
This commit is contained in:
David González Verdugo 2018-10-09 15:59:41 +02:00 committed by GitHub
commit 2fdf724eab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 3983 additions and 4439 deletions

View File

@ -14,12 +14,14 @@ allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
dependencies {
api 'org.apache.jackrabbit:jackrabbit-webdav:2.12.4'
api 'com.squareup.okhttp3:okhttp:3.10.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.51"
implementation 'com.gitlab.ownclouders:dav4android:oc_support'
}
android {
@ -52,4 +54,8 @@ android {
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<resources/>

View File

@ -34,8 +34,7 @@
android:targetSdkVersion="26"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light.NoTitleBar">
android:label="@string/app_name">
<activity
android:name="MainActivity"
android:configChanges="orientation|keyboardHidden"

View File

@ -42,4 +42,8 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

View File

@ -24,150 +24,99 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<EditText
android:id="@+id/server_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/button_check_server"
android:layout_toStartOf="@+id/button_check_server"
android:ems="10"
android:hint="Server address (with http or https)"
android:inputType="textPersonName"/>
<Button
android:id="@+id/button_check_server"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/server_address"
android:layout_alignBottom="@+id/server_address"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="onClickHandler"
android:text="@string/check_server"/>
<Button
android:id="@+id/button_refresh"
style="@style/ButtonStyle"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="@string/refresh"
android:onClick="onClickHandler"
/>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_below="@+id/button_refresh"
android:layout_above="@+id/button_upload"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@id/server_address"
android:layout_marginTop="10dp"
android:onClick="onClickHandler"
android:text="@string/refresh"/>
>
</ListView>
<Button
android:id="@+id/button_upload"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/ButtonStyle"
android:layout_alignParentLeft="true"
android:layout_below="@id/button_refresh"
android:layout_marginTop="10dp"
android:layout_above="@+id/frame"
android:text="@string/upload"
android:onClick="onClickHandler"
android:text="@string/upload"/>
/>
<TextView
android:id="@+id/upload_progress"
style="@style/ProgressStyle"
android:layout_below="@id/list_view"
android:layout_above="@id/frame"
android:layout_toRightOf="@id/button_upload"
android:layout_toLeftOf="@+id/button_delete_remote"
android:gravity="center"
android:textSize="14sp"
android:text="0%"
/>
<Button
android:id="@+id/button_download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/button_upload"
android:layout_marginTop="10dp"
android:id="@id/button_delete_remote"
style="@style/ButtonStyle"
android:layout_alignParentRight="true"
android:layout_above="@id/frame"
android:text="@string/delete_remote_file"
android:onClick="onClickHandler"
android:text="@string/download"/>
/>
<FrameLayout
android:id="@id/frame"
android:layout_width="match_parent"
android:layout_height="@dimen/frame_height"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_above="@+id/button_download"
>
</FrameLayout>
<Button
android:id="@+id/button_delete_remote"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@id/button_download"
style="@style/ButtonStyle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_below="@id/button_download"
android:layout_marginTop="10dp"
android:text="@string/download"
android:onClick="onClickHandler"
android:text="@string/delete_remote_file"/>
/>
<!--<ListView-->
<!--android:id="@+id/list_view"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:layout_below="@+id/button_refresh"-->
<!--android:visibility="invisible">-->
<!--</ListView>-->
<TextView
android:id="@+id/download_progress"
style="@style/ProgressStyle"
android:layout_below="@id/frame"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/button_download"
android:layout_toLeftOf="@+id/button_delete_local"
android:gravity="center"
android:textSize="14sp"
android:text="0%"
/>
<!--<TextView-->
<!--android:id="@+id/upload_progress"-->
<!--style="@style/ProgressStyle"-->
<!--android:layout_above="@id/frame"-->
<!--android:layout_below="@id/list_view"-->
<!--android:layout_toLeftOf="@+id/button_delete_remote"-->
<!--android:layout_toRightOf="@id/button_upload"-->
<!--android:enabled="false"-->
<!--android:gravity="center"-->
<!--android:text="0%"-->
<!--android:textSize="14sp"-->
<!--android:visibility="invisible"/>-->
<!--<Button-->
<!--android:id="@id/button_delete_remote"-->
<!--style="@style/ButtonStyle"-->
<!--android:layout_above="@id/frame"-->
<!--android:layout_alignParentRight="true"-->
<!--android:enabled="false"-->
<!--android:onClick="onClickHandler"-->
<!--android:text="@string/delete_remote_file"-->
<!--android:visibility="invisible"/>-->
<!--<FrameLayout-->
<!--android:id="@id/frame"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="@dimen/frame_height"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:layout_above="@+id/button_download"-->
<!--&gt;-->
<!--</FrameLayout>-->
<!--<Button-->
<!--android:id="@id/button_download"-->
<!--style="@style/ButtonStyle"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:enabled="false"-->
<!--android:onClick="onClickHandler"-->
<!--android:text="@string/download"-->
<!--android:visibility="invisible"/>-->
<!--<TextView-->
<!--android:id="@+id/download_progress"-->
<!--style="@style/ProgressStyle"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_below="@id/frame"-->
<!--android:layout_toLeftOf="@+id/button_delete_local"-->
<!--android:layout_toRightOf="@id/button_download"-->
<!--android:enabled="false"-->
<!--android:gravity="center"-->
<!--android:text="0%"-->
<!--android:textSize="14sp"-->
<!--android:visibility="invisible"/>-->
<!--<Button-->
<!--android:id="@id/button_delete_local"-->
<!--style="@style/ButtonStyle"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:enabled="false"-->
<!--android:onClick="onClickHandler"-->
<!--android:text="@string/delete_local_file"-->
<!--android:visibility="invisible"/>-->
<Button
android:id="@id/button_delete_local"
style="@style/ButtonStyle"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="@string/delete_local_file"
android:onClick="onClickHandler"
/>
</RelativeLayout>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2016 ownCloud GmbH.
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
@ -20,7 +20,6 @@
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.
-->
<resources>

View File

@ -26,7 +26,6 @@
<resources>
<string name="app_name">ownCloud Sample Client</string>
<string name="refresh">Refresh</string>
<string name="check_server">Check server</string>
<string name="upload">Upload</string>
<string name="delete_remote_file">Delete remote file</string>
<string name="download">Download</string>

View File

@ -1,8 +1,6 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
*
* @author David González Verdugo
*
* 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
@ -26,25 +24,30 @@
package com.owncloud.android.lib.sampleclient;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientFactory;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
@ -52,9 +55,6 @@ import com.owncloud.android.lib.resources.files.RemoteFile;
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -63,43 +63,17 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Credentials;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import static android.content.ContentValues.TAG;
public class MainActivity extends Activity implements OnRemoteOperationListener, OnDatatransferProgressListener {
private static String LOG_TAG = MainActivity.class.getCanonicalName();
private static final String NODE_VERSION = "version";
private static final String WEBDAV_PATH_4_0 = "/remote.php/webdav/";
private static final String NEW_WEBDAV_PATH = "/remote.php/dav/files/";
private static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
private static final String OC_X_OC_MTIME_HEADER = "X-OC-Mtime";
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String USER_AGENT_HEADER = "User-Agent";
private static final String CONTENT_TYPE_HEADER = "Content-Type";
private static final String USER_AGENT_VALUE = "Mozilla/5.0 (Android) ownCloud-android/2.7.0";
private static final String CONTENT_TYPE_VALUE = "multipart/form-data";
private Handler mHandler;
private OwnCloudClient mClient;
private FilesArrayAdapter mFilesAdapter;
private View mFrame;
private OkHttpClient mOkHttpClient;
private String mCredentials;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
@ -108,17 +82,20 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
mHandler = new Handler();
Uri serverUri = Uri.parse(getString(R.string.server_base_url));
final Uri serverUri = Uri.parse(getString(R.string.server_base_url));
OwnCloudClientManagerFactory.setUserAgent(getUserAgent());
mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true);
mClient.setCredentials(
OwnCloudCredentialsFactory.newBasicCredentials(
getString(R.string.username),
getString(R.string.password)
mClient.setCredentials(
OwnCloudCredentialsFactory.newBasicCredentials(
getString(R.string.username),
getString(R.string.password)
)
);
mFilesAdapter = new FilesArrayAdapter(this, R.layout.file_in_list);
// ((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter);
((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter);
// TODO move to background thread or task
AssetManager assets = getAssets();
@ -141,13 +118,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
Log.e(LOG_TAG, getString(R.string.error_copying_sample_file), e);
}
((TextView) findViewById(R.id.server_address)).setText(getString(R.string.server_base_url));
mOkHttpClient = new OkHttpClient();
mCredentials = Credentials.basic(getString(R.string.username), getString(R.string.password));
// mFrame = findViewById(R.id.frame);
mFrame = findViewById(R.id.frame);
}
@ -163,275 +134,77 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
public void onClickHandler(View button) {
switch (button.getId()) {
case R.id.button_check_server:
startCheck();
break;
case R.id.button_refresh:
startRefresh();
break;
case R.id.button_upload:
startUpload();
break;
case R.id.button_download:
startDownload();
break;
case R.id.button_delete_remote:
startRemoteDeletion();
break;
// case R.id.button_delete_local:
// startLocalDeletion();
// break;
case R.id.button_download:
startDownload();
break;
case R.id.button_delete_local:
startLocalDeletion();
break;
default:
Toast.makeText(this, R.string.youre_doing_it_wrong, Toast.LENGTH_SHORT).show();
}
}
private void startCheck() {
if (!validServerAddress()) return;
Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + "/status.php")
.get()
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
}
try { // Successful response
String jsonData = response.body().string();
JSONObject Jobject = new JSONObject(jsonData);
final String serverVersion = Jobject.get("version").toString();
showMessage("Server with version " + serverVersion + " detected");
} catch (JSONException e) {
e.printStackTrace();
}
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
}
@Override public void onFailure(Call call, final IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
}
private void startRefresh() {
// Let's first use OKHttp with the new endpoint without depending on our library operations
// ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(FileUtils.PATH_SEPARATOR);
// refreshOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username))
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.method("PROPFIND", null)
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
final String propFindResult = response.body().string();
showMessage(propFindResult);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
}
}
@Override public void onFailure(Call call, IOException e) {
showMessage("Something was wrong: " + e.toString());
e.printStackTrace();
}
});
}
private void startRefresh() {
ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(FileUtils.PATH_SEPARATOR);
refreshOperation.execute(mClient, this, mHandler);
}
private void startUpload() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
final File fileToUpload = upFolder.listFiles()[0];
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
String mimeType = getString(R.string.sample_file_mimetype);
MediaType mediaType = MediaType.parse(mimeType);
// Get the last modification date of the file from the file system
Long timeStampLong = fileToUpload.lastModified()/1000;
String timeStamp = timeStampLong.toString();
// Let's first use OKHttp with the new endpoint without depending on our library operations
// UploadRemoteFileOperation uploadOperation = new UploadRemoteFileOperation(fileToUpload.getAbsolutePath(), remotePath, mimeType, timeStamp);
// uploadOperation.addDatatransferProgressListener(this);
// uploadOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
RequestBody requestBody = RequestBody.create(mediaType, fileToUpload);
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username) + remotePath)
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.addHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE_VALUE)
.addHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(fileToUpload.length()))
.addHeader(OC_X_OC_MTIME_HEADER, timeStamp)
.put(requestBody)
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
showMessage("Successful upload of " + fileToUpload.getName());
}
}
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
UploadRemoteFileOperation uploadOperation = new UploadRemoteFileOperation(fileToUpload.getAbsolutePath(),
remotePath, mimeType, timeStamp);
uploadOperation.addDatatransferProgressListener(this);
uploadOperation.execute(mClient, this, mHandler);
}
private void startDownload() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
downFolder.mkdir();
private void startRemoteDeletion() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
final File fileToUpload = upFolder.listFiles()[0];
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
// Let's first use OKHttp with the new endpoint without depending on our library operations
// DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remotePath, downFolder.getAbsolutePath());
// downloadOperation.addDatatransferProgressListener(this);
// downloadOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username) + remotePath)
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.get()
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
showMessage("Successful download of " + fileToUpload.getName() + " although local file " +
"won't be created in this stage");
}
}
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
}
private void startRemoteDeletion() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
final File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
// Let's first use OKHttp with the new endpoint without depending on our library operations
// RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath);
// removeOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username) + remotePath)
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.delete()
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
showMessage("Successful deletion of " + fileToUpload.getName());
}
}
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath);
removeOperation.execute(mClient, this, mHandler);
}
private void startDownload() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
downFolder.mkdir();
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remotePath,
downFolder.getAbsolutePath());
downloadOperation.addDatatransferProgressListener(this);
downloadOperation.execute(mClient, this, mHandler);
}
@SuppressWarnings("deprecation")
private void startLocalDeletion() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
File downloadedFile = downFolder.listFiles()[0];
if (!downloadedFile.delete() && downloadedFile.exists()) {
Toast.makeText(this, R.string.error_deleting_local_file, Toast.LENGTH_SHORT).show();
} else {
// ((TextView) findViewById(R.id.download_progress)).setText("0%");
// findViewById(R.id.frame).setBackgroundDrawable(null);
((TextView) findViewById(R.id.download_progress)).setText("0%");
findViewById(R.id.frame).setBackgroundDrawable(null);
}
}
@ -444,14 +217,14 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
} else if (operation instanceof ReadRemoteFolderOperation) {
onSuccessfulRefresh((ReadRemoteFolderOperation)operation, result);
} else if (operation instanceof UploadRemoteFileOperation ) {
onSuccessfulUpload((UploadRemoteFileOperation)operation, result);
} else if (operation instanceof com.owncloud.android.lib.resources.files.UploadRemoteFileOperation) {
onSuccessfulUpload((com.owncloud.android.lib.resources.files.UploadRemoteFileOperation)operation, result);
} else if (operation instanceof RemoveRemoteFileOperation ) {
onSuccessfulRemoteDeletion((RemoveRemoteFileOperation)operation, result);
} else if (operation instanceof DownloadRemoteFileOperation ) {
onSuccessfulDownload((DownloadRemoteFileOperation)operation, result);
onSuccessfulDownload();
} else {
Toast.makeText(this, R.string.todo_operation_finished_in_success, Toast.LENGTH_SHORT).show();
@ -460,9 +233,9 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
private void onSuccessfulRefresh(ReadRemoteFolderOperation operation, RemoteOperationResult result) {
mFilesAdapter.clear();
List<RemoteFile> files = new ArrayList<RemoteFile>();
for(Object obj: result.getData()) {
files.add((RemoteFile) obj);
List<RemoteFile> files = new ArrayList<>();
for(RemoteFile remoteFile: (List<RemoteFile>) result.getData()) {
files.add(remoteFile);
}
if (files != null) {
Iterator<RemoteFile> it = files.iterator();
@ -474,20 +247,19 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
mFilesAdapter.notifyDataSetChanged();
}
private void onSuccessfulUpload(UploadRemoteFileOperation operation, RemoteOperationResult result) {
private void onSuccessfulUpload(com.owncloud.android.lib.resources.files.UploadRemoteFileOperation operation, RemoteOperationResult result) {
startRefresh();
}
private void onSuccessfulRemoteDeletion(RemoveRemoteFileOperation operation, RemoteOperationResult result) {
startRefresh();
// TextView progressView = (TextView) findViewById(R.id.upload_progress);
// if (progressView != null) {
// progressView.setText("0%");
// }
TextView progressView = (TextView) findViewById(R.id.upload_progress);
if (progressView != null) {
progressView.setText("0%");
}
}
@SuppressWarnings("deprecation")
private void onSuccessfulDownload(DownloadRemoteFileOperation operation, RemoteOperationResult result) {
private void onSuccessfulDownload() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
File downloadedFile = downFolder.listFiles()[0];
BitmapDrawable bDraw = new BitmapDrawable(getResources(), downloadedFile.getAbsolutePath());
@ -503,11 +275,11 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
@Override
public void run() {
TextView progressView = null;
// if (upload) {
// progressView = (TextView) findViewById(R.id.upload_progress);
// } else {
// progressView = (TextView) findViewById(R.id.download_progress);
// }
if (upload) {
progressView = findViewById(R.id.upload_progress);
} else {
progressView = findViewById(R.id.download_progress);
}
if (progressView != null) {
progressView.setText(Long.toString(percentage) + "%");
}
@ -515,32 +287,24 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
});
}
private boolean validServerAddress() {
// user agent
@SuppressLint("StringFormatInvalid")
private String getUserAgent() {
String appString = getResources().getString(R.string.user_agent);
String packageName = getPackageName();
String version = "";
String serverAddress = ((TextView) findViewById(R.id.server_address)).getText().toString();
if (serverAddress.equals("") || (!serverAddress.contains("http://") && !serverAddress.contains("https://"))) {
showToastMessage("Introduce a proper server address with http/https");
return false;
}
return true;
}
private void showMessage(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
showToastMessage(message);
PackageInfo pInfo;
try {
pInfo = getPackageManager().getPackageInfo(packageName, 0);
if (pInfo != null) {
version = pInfo.versionName;
}
});
}
} catch (PackageManager.NameNotFoundException e) {
Log_OC.e(TAG, "Trying to get packageName", e.getCause());
}
private void showToastMessage(String message) {
Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
// Mozilla/5.0 (Android) ownCloud-android/1.7.0
return String.format(appString, version);
}
}

View File

@ -56,11 +56,8 @@ public class DynamicSessionManager implements OwnCloudClientManager {
}
@Override
public void saveAllClients(Context context, String accountType)
throws AccountUtils.AccountNotFoundException,
AuthenticatorException, IOException, OperationCanceledException {
public void saveAllClients(Context context, String accountType) {
mSimpleFactoryManager.saveAllClients(context, accountType);
mSingleSessionManager.saveAllClients(context, accountType);
}
}

View File

@ -116,9 +116,8 @@ public class OwnCloudAccount {
* @throws IOException
* @throws OperationCanceledException
*/
public void loadCredentials(Context context)
throws AccountNotFoundException, AuthenticatorException,
IOException, OperationCanceledException {
public void loadCredentials(Context context) throws AuthenticatorException,
IOException, OperationCanceledException {
if (context == null) {
throw new IllegalArgumentException("Parameter 'context' cannot be null");

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
* Copyright (C) 2018 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -25,64 +25,51 @@
package com.owncloud.android.lib.common;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.params.HttpParams;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
import android.content.Context;
import android.net.Uri;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
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 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 {
public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";
public static final String NEW_WEBDAV_FILES_PATH_4_0 = "/remote.php/dav/files/";
public static final String NEW_WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
public static final String STATUS_PATH = "/status.php";
public static final String FILES_WEB_PATH = "/index.php/apps/files";
private static final String TAG = OwnCloudClient.class.getSimpleName();
private static final int MAX_REDIRECTIONS_COUNT = 3;
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
private static final String PARAM_PROTOCOL_VERSION = "http.protocol.version";
private static byte[] sExhaustBuffer = new byte[1024];
private static int sIntanceCounter = 0;
private boolean mFollowRedirects = true;
private OwnCloudCredentials mCredentials = null;
private int mInstanceNumber = 0;
private Uri mBaseUri;
private OwnCloudVersion mVersion = null;
/// next too attributes are a very ugly dependency, added to grant silent retry of OAuth token when needed ;
/// see #shouldInvalidateCredentials and #invalidateCredentials for more details
private Context mContext;
private OwnCloudAccount mAccount;
/**
@ -91,20 +78,11 @@ public class OwnCloudClient extends HttpClient {
*/
private OwnCloudClientManager mOwnCloudClientManager = null;
/**
* When 'true', the method {@link #executeMethod(HttpMethod)} tries to silently refresh credentials
* if fails due to lack of authorization, if credentials support authorization refresh.
*/
private boolean mSilentRefreshOfAccountCredentials = true;
private String mRedirectedLocation;
private boolean mFollowRedirects;
/**
* Constructor
*/
public OwnCloudClient(Uri baseUri, HttpConnectionManager connectionMgr) {
super(connectionMgr);
public OwnCloudClient(Uri baseUri) {
if (baseUri == null) {
throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL");
}
@ -113,45 +91,10 @@ public class OwnCloudClient extends HttpClient {
mInstanceNumber = sIntanceCounter++;
Log_OC.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient");
String userAgent = OwnCloudClientManagerFactory.getUserAgent();
getParams().setParameter(HttpMethodParams.USER_AGENT, userAgent);
getParams().setParameter(
PARAM_PROTOCOL_VERSION,
HttpVersion.HTTP_1_1
);
getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
getParams().setParameter(
PARAM_SINGLE_COOKIE_HEADER, // to avoid problems with some web servers
PARAM_SINGLE_COOKIE_HEADER_VALUE
);
applyProxySettings();
clearCredentials();
clearCookies();
}
private void applyProxySettings() {
String proxyHost = System.getProperty("http.proxyHost");
String proxyPortSt = System.getProperty("http.proxyPort");
int proxyPort = 0;
try {
if (proxyPortSt != null && proxyPortSt.length() > 0) {
proxyPort = Integer.parseInt(proxyPortSt);
}
} catch (Exception e) {
Log_OC.w(TAG, "Proxy port could not be read, keeping default value " + proxyPort);
}
if (proxyHost != null && proxyHost.length() > 0) {
HostConfiguration hostCfg = getHostConfiguration();
hostCfg.setProxy(proxyHost, proxyPort);
Log_OC.d(TAG, "Proxy settings: " + proxyHost + ":" + proxyPort);
}
}
public void setCredentials(OwnCloudCredentials credentials) {
if (credentials != null) {
mCredentials = credentials;
@ -168,74 +111,28 @@ public class OwnCloudClient extends HttpClient {
mCredentials.applyTo(this);
}
/**
* Requests the received method with the received timeout (milliseconds).
*
* Executes the method through the inherited HttpClient.executedMethod(method).
*
* Sets the socket and connection timeouts only for the method received.
*
* The timeouts are both in milliseconds; 0 means 'infinite';
* < 0 means 'do not change the default'
*
* @param method HTTP method request.
* @param readTimeout Timeout to set for data reception
* @param connectionTimeout Timeout to set for connection establishment
*/
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws IOException {
int oldSoTimeout = getParams().getSoTimeout();
int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
try {
if (readTimeout >= 0) {
method.getParams().setSoTimeout(readTimeout); // this should be enough...
getParams().setSoTimeout(readTimeout); // ... but HTTPS needs this
}
if (connectionTimeout >= 0) {
getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
}
return executeMethod(method);
} finally {
getParams().setSoTimeout(oldSoTimeout);
getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
}
public void applyCredentials() {
mCredentials.applyTo(this);
}
/**
* Requests the received method.
*
* Executes the method through the inherited HttpClient.executedMethod(method).
*
* @param method HTTP method request.
*/
@Override
public int executeMethod(HttpMethod method) throws IOException {
public int executeHttpMethod (HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
int repeatCounter = 0;
int status;
do {
// Update User Agent
HttpParams params = method.getParams();
String userAgent = OwnCloudClientManagerFactory.getUserAgent();
params.setParameter(HttpMethodParams.USER_AGENT, userAgent);
// Clean previous request id. This is a bit hacky but is the only way to add request headers in WebDAV
// methods by using Dav4Android
deleteHeaderForAllRequests(OC_X_REQUEST_ID);
preventCrashDueToInvalidPort(method);
Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " +
method.getName() + " " + method.getPath());
//logCookiesAtRequest(method.getRequestHeaders(), "before");
//logCookiesAtState("before");
method.setFollowRedirects(false);
status = super.executeMethod(method);
// Header to allow tracing requests in apache and ownCloud logs
addHeaderForAllRequests(OC_X_REQUEST_ID,
RandomUtils.generateRandomString(RandomUtils.generateRandomInteger(20, 200)));
status = method.execute();
checkFirstRedirection(method);
if (mFollowRedirects) {
if(mFollowRedirects && !isIdPRedirection()) {
status = followRedirection(method).getLastStatus();
}
@ -243,109 +140,90 @@ public class OwnCloudClient extends HttpClient {
if (repeatWithFreshCredentials) {
repeatCounter++;
}
} while (repeatWithFreshCredentials);
//logCookiesAtRequest(method.getRequestHeaders(), "after");
//logCookiesAtState("after");
//logSetCookiesAtResponse(method.getResponseHeaders());
return status;
}
private void checkFirstRedirection(HttpMethod method) {
Header[] httpHeaders = method.getResponseHeaders();
private void checkFirstRedirection(HttpBaseMethod method) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
if(location != null && !location.isEmpty()) {
mRedirectedLocation = location;
}
}
for (Header httpHeader : httpHeaders) {
private int executeRedirectedHttpMethod (HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
int repeatCounter = 0;
int status;
if ("location".equals(httpHeader.getName().toLowerCase())) {
mRedirectedLocation = httpHeader.getValue();
break;
do {
status = method.execute();
repeatWithFreshCredentials = checkUnauthorizedAccess(status, repeatCounter);
if (repeatWithFreshCredentials) {
repeatCounter++;
}
}
} while (repeatWithFreshCredentials);
return status;
}
/**
* Fix for https://github.com/owncloud/android/issues/1847#issuecomment-267558274
*
* The problem: default SocketFactory in HTTPClient 3.x for HTTP connections creates a separate thread
* to create the socket. When a port out of TCP bounds is passed, an exception is thrown in that
* separate thread, and our original thread is not able to catch it. This is not happenning with HTTPS
* connections because we had to define our own socket factory,
* {@link com.owncloud.android.lib.common.network.AdvancedSslSocketFactory}, and it does not mess with
* threads.
*
* The solution: validate the input (the port number) ourselves before let the work to HTTPClient 3.x.
*
* @param method HTTP method to run.
* @throws IllegalArgumentException If 'method' targets an invalid port in an HTTP URI.
* @throws URIException If the URI to the target server cannot be built.
*/
private void preventCrashDueToInvalidPort(HttpMethod method) throws URIException {
int port = method.getURI().getPort();
String scheme = method.getURI().getScheme().toLowerCase();
if ("http".equals(scheme) && port > 0xFFFF) {
// < 0 is not tested because -1 is used when no port number is specified in the URL;
// no problem, the network library will convert that in the default HTTP port
throw new IllegalArgumentException("Invalid port number " + port);
}
}
public RedirectionPath followRedirection(HttpMethod method) throws IOException {
public RedirectionPath followRedirection(HttpBaseMethod method) throws Exception {
int redirectionsCount = 0;
int status = method.getStatusCode();
RedirectionPath result = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
RedirectionPath redirectionPath = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
(status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY ||
status == HttpStatus.SC_TEMPORARY_REDIRECT)
) {
(status == HttpConstants.HTTP_MOVED_PERMANENTLY ||
status == HttpConstants.HTTP_MOVED_TEMPORARILY ||
status == HttpConstants.HTTP_TEMPORARY_REDIRECT)
) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER) != null
? method.getResponseHeader(HttpConstants.LOCATION_HEADER)
: method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
Header location = method.getResponseHeader("Location");
if (location == null) {
location = method.getResponseHeader("location");
}
if (location != null) {
String locationStr = location.getValue();
Log_OC.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + locationStr);
"Location to redirect: " + location);
result.addLocation(locationStr);
redirectionPath.addLocation(location);
// Release the connection to avoid reach the max number of connections per host
// due to it will be set a different url
exhaustResponse(method.getResponseBodyAsStream());
method.releaseConnection();
method.setURI(new URI(locationStr, true));
Header destination = method.getRequestHeader("Destination");
if (destination == null) {
destination = method.getRequestHeader("destination");
}
method.setUrl(HttpUrl.parse(location));
final String destination = method.getRequestHeader("Destination") != null
? method.getRequestHeader("Destination")
: method.getRequestHeader("destination");
if (destination != null) {
int suffixIndex = locationStr.lastIndexOf(WEBDAV_PATH_4_0);
String redirectionBase = locationStr.substring(0, suffixIndex);
final int suffixIndex = location.lastIndexOf(getNewFilesWebDavUri().toString());
final String redirectionBase = location.substring(0, suffixIndex);
final String destinationPath = destination.substring(mBaseUri.toString().length());
String destinationStr = destination.getValue();
String destinationPath = destinationStr.substring(mBaseUri.toString().length());
String redirectedDestination = redirectionBase + destinationPath;
destination.setValue(redirectedDestination);
method.setRequestHeader(destination);
method.setRequestHeader("destination", redirectionBase + destinationPath);
}
status = super.executeMethod(method);
result.addStatus(status);
try {
status = executeRedirectedHttpMethod(method);
} catch (HttpException e) {
if(e.getMessage().contains(Integer.toString(HttpConstants.HTTP_MOVED_TEMPORARILY))) {
status = HttpConstants.HTTP_MOVED_TEMPORARILY;
} else {
throw e;
}
}
redirectionPath.addStatus(status);
redirectionsCount++;
} else {
Log_OC.d(TAG + " #" + mInstanceNumber, "No location to redirect!");
status = HttpStatus.SC_NOT_FOUND;
status = HttpConstants.HTTP_NOT_FOUND;
}
}
return result;
return redirectionPath;
}
/**
@ -361,26 +239,21 @@ public class OwnCloudClient extends HttpClient {
} catch (IOException io) {
Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" +
" will be IGNORED", io);
" will be IGNORED", io);
}
}
}
/**
* Sets the connection and wait-for-data timeouts to be applied by default to the methods
* performed by this client.
*/
public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
if (defaultDataTimeout >= 0) {
getParams().setSoTimeout(defaultDataTimeout);
}
if (defaultConnectionTimeout >= 0) {
getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
}
public Uri getNewFilesWebDavUri() {
return mCredentials instanceof OwnCloudAnonymousCredentials
? Uri.parse(mBaseUri + NEW_WEBDAV_FILES_PATH_4_0)
: Uri.parse(mBaseUri + NEW_WEBDAV_FILES_PATH_4_0 + mCredentials.getUsername());
}
public Uri getWebdavUri() {
return Uri.parse(mBaseUri + WEBDAV_PATH_4_0);
public Uri getNewUploadsWebDavUri() {
return mCredentials instanceof OwnCloudAnonymousCredentials
? Uri.parse(mBaseUri + NEW_WEBDAV_UPLOADS_PATH_4_0)
: Uri.parse(mBaseUri + NEW_WEBDAV_UPLOADS_PATH_4_0 + mCredentials.getUsername());
}
/**
@ -405,52 +278,32 @@ public class OwnCloudClient extends HttpClient {
return mCredentials;
}
public void setFollowRedirects(boolean followRedirects) {
mFollowRedirects = followRedirects;
private void logCookie(Cookie cookie) {
Log_OC.d(TAG, "Cookie name: " + cookie.name());
Log_OC.d(TAG, " value: " + cookie.value());
Log_OC.d(TAG, " domain: " + cookie.domain());
Log_OC.d(TAG, " path: " + cookie.path());
Log_OC.d(TAG, " expiryDate: " + cookie.expiresAt());
Log_OC.d(TAG, " secure: " + cookie.secure());
}
public boolean getFollowRedirects() {
return mFollowRedirects;
}
private void logCookiesAtRequest(Header[] headers, String when) {
private void logCookiesAtRequest(Headers headers, String when) {
int counter = 0;
for (int i = 0; i < headers.length; i++) {
if (headers[i].getName().toLowerCase().equals("cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Cookies at request (" + when + ") (" + counter++ + "): " +
headers[i].getValue());
}
for (final String cookieHeader : headers.toMultimap().get("cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Cookies at request (" + when + ") (" + counter++ + "): "
+ cookieHeader);
}
if (counter == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No cookie at request before");
}
}
private void logCookiesAtState(String string) {
Cookie[] cookies = getState().getCookies();
if (cookies.length == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No cookie at STATE before");
} else {
Log_OC.d(TAG + " #" + mInstanceNumber, "Cookies at STATE (before)");
for (int i = 0; i < cookies.length; i++) {
Log_OC.d(TAG + " #" + mInstanceNumber, " (" + i + "):" +
"\n name: " + cookies[i].getName() +
"\n value: " + cookies[i].getValue() +
"\n domain: " + cookies[i].getDomain() +
"\n path: " + cookies[i].getPath()
);
}
}
}
private void logSetCookiesAtResponse(Header[] headers) {
private void logSetCookiesAtResponse(Headers headers) {
int counter = 0;
for (int i = 0; i < headers.length; i++) {
if (headers[i].getName().toLowerCase().equals("set-cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Set-Cookie (" + counter++ + "): " + headers[i].getValue());
}
for (final String cookieHeader : headers.toMultimap().get("set-cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Set-Cookie (" + counter++ + "): " + cookieHeader);
}
if (counter == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No set-cookie");
@ -458,39 +311,25 @@ public class OwnCloudClient extends HttpClient {
}
public String getCookiesString() {
Cookie[] cookies = getState().getCookies();
String cookiesString = "";
for (Cookie cookie : cookies) {
cookiesString = cookiesString + cookie.toString() + ";";
List<Cookie> cookieList = getCookiesFromUrl(HttpUrl.parse(mBaseUri.toString()));
// logCookie(cookie);
if (cookieList != null) {
for (Cookie cookie : cookieList) {
cookiesString += cookie.toString() + ";";
}
}
return cookiesString;
}
public int getConnectionTimeout() {
return getHttpConnectionManager().getParams().getConnectionTimeout();
public void setCookiesForCurrentAccount(List<Cookie> cookies) {
getOkHttpClient().cookieJar().saveFromResponse(
HttpUrl.parse(getAccount().getBaseUri().toString()),
cookies
);
}
public int getDataTimeout() {
return getParams().getSoTimeout();
}
private void logCookie(Cookie cookie) {
Log_OC.d(TAG, "Cookie name: " + cookie.getName());
Log_OC.d(TAG, " value: " + cookie.getValue());
Log_OC.d(TAG, " domain: " + cookie.getDomain());
Log_OC.d(TAG, " path: " + cookie.getPath());
Log_OC.d(TAG, " version: " + cookie.getVersion());
Log_OC.d(TAG, " expiryDate: " +
(cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--"));
Log_OC.d(TAG, " comment: " + cookie.getComment());
Log_OC.d(TAG, " secure: " + cookie.getSecure());
}
public void setOwnCloudVersion(OwnCloudVersion version) {
mVersion = version;
}
@ -499,14 +338,6 @@ public class OwnCloudClient extends HttpClient {
return mVersion;
}
public void setContext(Context context) {
this.mContext = context;
}
public Context getContext() {
return mContext;
}
public void setAccount(OwnCloudAccount account) {
this.mAccount = account;
}
@ -515,18 +346,6 @@ public class OwnCloudClient extends HttpClient {
return mAccount;
}
/**
* Enables or disables silent refresh of credentials, if supported by credentials themselves.
*/
public void setSilentRefreshOfAccountCredentials(boolean silentRefreshOfAccountCredentials) {
mSilentRefreshOfAccountCredentials = silentRefreshOfAccountCredentials;
}
public boolean getSilentRefreshOfAccountCredentials() {
return mSilentRefreshOfAccountCredentials;
}
/**
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
*
@ -546,19 +365,19 @@ public class OwnCloudClient extends HttpClient {
if (invalidated) {
if (getCredentials().authTokenCanBeRefreshed() &&
repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) {
repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) {
try {
mAccount.loadCredentials(mContext);
mAccount.loadCredentials(getContext());
// if mAccount.getCredentials().length() == 0 --> refresh failed
setCredentials(mAccount.getCredentials());
credentialsWereRefreshed = true;
} catch (AccountsException | IOException e) {
Log_OC.e(
TAG,
"Error while trying to refresh auth token for " + mAccount.getSavedAccount().name,
e
TAG,
"Error while trying to refresh auth token for " + mAccount.getSavedAccount().name,
e
);
}
}
@ -569,7 +388,7 @@ public class OwnCloudClient extends HttpClient {
mOwnCloudClientManager.removeClientFor(mAccount);
}
}
// else: execute will finish with status 401
// else: onExecute will finish with status 401
}
return credentialsWereRefreshed;
@ -586,13 +405,13 @@ public class OwnCloudClient extends HttpClient {
*/
private boolean shouldInvalidateAccountCredentials(int httpStatusCode) {
boolean should = (httpStatusCode == HttpStatus.SC_UNAUTHORIZED || isIdPRedirection()); // invalid credentials
boolean should = (httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED || isIdPRedirection()); // invalid credentials
should &= (mCredentials != null && // real credentials
!(mCredentials instanceof OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials));
!(mCredentials instanceof OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials));
// test if have all the needed to effectively invalidate ...
should &= (mAccount != null && mAccount.getSavedAccount() != null && mContext != null);
should &= (mAccount != null && mAccount.getSavedAccount() != null && getContext() != null);
return should;
}
@ -606,10 +425,10 @@ public class OwnCloudClient extends HttpClient {
* @return 'True' if invalidation was successful, 'false' otherwise.
*/
private boolean invalidateAccountCredentials() {
AccountManager am = AccountManager.get(mContext);
AccountManager am = AccountManager.get(getContext());
am.invalidateAuthToken(
mAccount.getSavedAccount().type,
mCredentials.getAuthToken()
mAccount.getSavedAccount().type,
mCredentials.getAuthToken()
);
am.clearPassword(mAccount.getSavedAccount()); // being strict, only needed for Basic Auth credentials
return true;
@ -632,4 +451,12 @@ public class OwnCloudClient extends HttpClient {
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
}
public boolean followRedirects() {
return mFollowRedirects;
}
public void setFollowRedirects(boolean followRedirects) {
this.mFollowRedirects = followRedirects;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,9 +24,6 @@
package com.owncloud.android.lib.common;
import java.io.IOException;
import java.security.GeneralSecurityException;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
@ -40,22 +37,15 @@ import android.os.Bundle;
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.io.IOException;
public class OwnCloudClientFactory {
final private static String TAG = OwnCloudClientFactory.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;
/**
* Creates a OwnCloudClient setup for an ownCloud account
*
@ -122,9 +112,6 @@ public class OwnCloudClientFactory {
} else {
//String password = am.getPassword(account);
//String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(),
// false);
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
@ -162,24 +149,12 @@ public class OwnCloudClientFactory {
*/
public static OwnCloudClient createOwnCloudClient(Uri uri, Context context,
boolean followRedirects) {
try {
NetworkUtils.registerAdvancedSslContext(true, context);
} catch (GeneralSecurityException e) {
Log_OC.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in" +
" the system will be used for HTTPS connections", e);
OwnCloudClient client = new OwnCloudClient(uri);
} catch (IOException e) {
Log_OC.e(TAG, "The local server truststore could not be read. Default SSL management" +
" in the system will be used for HTTPS connections", e);
}
OwnCloudClient client = new OwnCloudClient(uri, NetworkUtils.getMultiThreadedConnManager());
client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
client.setFollowRedirects(followRedirects);
client.setContext(context);
return client;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -32,24 +32,23 @@ import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
/**
* Manager to create and reuse OwnCloudClient instances to access remote OC servers.
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
*/
public interface OwnCloudClientManager {
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context)
throws AccountNotFoundException, OperationCanceledException, AuthenticatorException,
OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws AccountNotFoundException,
OperationCanceledException, AuthenticatorException,
IOException;
public OwnCloudClient removeClientFor(OwnCloudAccount account);
OwnCloudClient removeClientFor(OwnCloudAccount account);
public void saveAllClients(Context context, String accountType)
void saveAllClients(Context context, String accountType)
throws AccountNotFoundException, AuthenticatorException,
IOException, OperationCanceledException;
}

View File

@ -100,5 +100,4 @@ public class OwnCloudClientManagerFactory {
}
return false;
}
}

View File

@ -40,9 +40,8 @@ public class SimpleFactoryManager implements OwnCloudClientManager {
private static final String TAG = SimpleFactoryManager.class.getSimpleName();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context)
throws AccountNotFoundException, OperationCanceledException, AuthenticatorException,
IOException {
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws
OperationCanceledException, AuthenticatorException, IOException {
Log_OC.d(TAG, "getClientFor(OwnCloudAccount ... : ");

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,14 +24,8 @@
package com.owncloud.android.lib.common;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
@ -39,17 +33,23 @@ import android.net.Uri;
import android.util.Log;
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.OwnCloudSamlSsoCredentials;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Implementation of {@link OwnCloudClientManager}
* <p>
*
* TODO check multithreading safety
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class SingleSessionManager implements OwnCloudClientManager {
@ -57,16 +57,15 @@ public class SingleSessionManager implements OwnCloudClientManager {
private static final String TAG = SingleSessionManager.class.getSimpleName();
private ConcurrentMap<String, OwnCloudClient> mClientsWithKnownUsername =
new ConcurrentHashMap<String, OwnCloudClient>();
new ConcurrentHashMap<>();
private ConcurrentMap<String, OwnCloudClient> mClientsWithUnknownUsername =
new ConcurrentHashMap<String, OwnCloudClient>();
new ConcurrentHashMap<>();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context)
throws AccountNotFoundException, OperationCanceledException, AuthenticatorException,
IOException {
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws OperationCanceledException,
AuthenticatorException, IOException {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "getClientFor starting ");
@ -80,8 +79,7 @@ public class SingleSessionManager implements OwnCloudClientManager {
String sessionName = account.getCredentials() == null ? "" :
AccountUtils.buildAccountName(
account.getBaseUri(),
account.getCredentials().getAuthToken()
);
account.getCredentials().getAuthToken());
if (accountName != null) {
client = mClientsWithKnownUsername.get(accountName);
@ -115,16 +113,17 @@ public class SingleSessionManager implements OwnCloudClientManager {
account.getBaseUri(),
context.getApplicationContext(),
true); // TODO remove dependency on OwnCloudClientFactory
client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
client.setAccount(account);
client.setContext(context);
client.setOwnCloudClientManager(this);
// enable cookie tracking
AccountUtils.restoreCookies(account.getSavedAccount(), client, context);
account.loadCredentials(context);
client.setCredentials(account.getCredentials());
if (client.getCredentials() instanceof OwnCloudSamlSsoCredentials) {
client.disableAutomaticCookiesHandling();
}
if (accountName != null) {
mClientsWithKnownUsername.put(accountName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@ -141,7 +140,9 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (!reusingKnown && Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for session " + sessionName);
}
keepCredentialsUpdated(account, client);
keepCredentialsUpdated(client);
keepCookiesUpdated(context, account, client);
keepUriUpdated(account, client);
}
@ -154,7 +155,6 @@ public class SingleSessionManager implements OwnCloudClientManager {
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "removeClientFor starting ");
}
@ -185,14 +185,11 @@ public class SingleSessionManager implements OwnCloudClientManager {
Log_OC.d(TAG, "removeClientFor finishing ");
}
return null;
}
@Override
public void saveAllClients(Context context, String accountType)
throws AccountNotFoundException, AuthenticatorException, IOException,
OperationCanceledException {
public void saveAllClients(Context context, String accountType) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "Saving sessions... ");
@ -215,14 +212,19 @@ public class SingleSessionManager implements OwnCloudClientManager {
}
}
private void keepCredentialsUpdated(OwnCloudClient reusedClient) {
reusedClient.applyCredentials();
}
private void keepCredentialsUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) {
OwnCloudCredentials recentCredentials = account.getCredentials();
if (recentCredentials != null && !recentCredentials.getAuthToken().equals(
reusedClient.getCredentials().getAuthToken())) {
reusedClient.setCredentials(recentCredentials);
private void keepCookiesUpdated(Context context, OwnCloudAccount account, OwnCloudClient reusedClient) {
AccountManager am = AccountManager.get(context.getApplicationContext());
if (am != null && account.getSavedAccount() != null) {
String recentCookies = am.getUserData(account.getSavedAccount(), AccountUtils.Constants.KEY_COOKIES);
String previousCookies = reusedClient.getCookiesString();
if (recentCookies != null && previousCookies != "" && !recentCookies.equals(previousCookies)) {
AccountUtils.restoreCookies(account.getSavedAccount(), reusedClient, context);
}
}
}
// this method is just a patch; we need to distinguish accounts in the same host but
@ -232,8 +234,5 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (!recentUri.equals(reusedClient.getBaseUri())) {
reusedClient.setBaseUri(recentUri);
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
* Copyright (C) 2018 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -25,11 +25,6 @@
package com.owncloud.android.lib.common.accounts;
import java.io.IOException;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpStatus;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
@ -38,15 +33,19 @@ import android.accounts.OperationCanceledException;
import android.content.Context;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
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 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();
@ -61,11 +60,23 @@ public class AccountUtils {
*/
public static String getWebDavUrlForAccount(Context context, Account account)
throws AccountNotFoundException {
String webDavUrlForAccount = "";
return getBaseUrlForAccount(context, account) + OwnCloudClient.WEBDAV_PATH_4_0;
try {
OwnCloudCredentials ownCloudCredentials = getCredentialsForAccount(context, account);
webDavUrlForAccount = getBaseUrlForAccount(context, account) + OwnCloudClient.NEW_WEBDAV_FILES_PATH_4_0
+ ownCloudCredentials.getUsername();
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return webDavUrlForAccount;
}
/**
* Extracts url server from the account
*
@ -86,7 +97,6 @@ public class AccountUtils {
return baseurl;
}
/**
* Get the username corresponding to an OC account.
*
@ -132,7 +142,7 @@ public class AccountUtils {
public static OwnCloudCredentials getCredentialsForAccount(Context context, Account account)
throws OperationCanceledException, AuthenticatorException, IOException {
OwnCloudCredentials credentials = null;
OwnCloudCredentials credentials;
AccountManager am = AccountManager.get(context);
String supportsOAuth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2);
@ -176,10 +186,8 @@ public class AccountUtils {
}
return credentials;
}
public static String buildAccountNameOld(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
@ -207,7 +215,6 @@ public class AccountUtils {
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
// Account Manager
AccountManager ac = AccountManager.get(context.getApplicationContext());
@ -215,13 +222,11 @@ 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 );
}
}
}
/**
* Restore the client cookies persisted in an account stored in the system AccountManager.
*
@ -239,23 +244,28 @@ public class AccountUtils {
// Account Manager
AccountManager am = AccountManager.get(context.getApplicationContext());
Uri serverUri = (client.getBaseUri() != null) ? client.getBaseUri() : client.getWebdavUri();
Uri serverUri = (client.getBaseUri() != null) ? client.getBaseUri() : client.getNewFilesWebDavUri();
String cookiesString = am.getUserData(account, Constants.KEY_COOKIES);
if (cookiesString != null) {
String[] cookies = cookiesString.split(";");
if (cookies.length > 0) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = new Cookie();
int equalPos = cookies[i].indexOf('=');
cookie.setName(cookies[i].substring(0, equalPos));
cookie.setValue(cookies[i].substring(equalPos + 1));
cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT
cookie.setPath(serverUri.getPath()); // VERY IMPORTANT
client.getState().addCookie(cookie);
}
String[] rawCookies = cookiesString.split(";");
List<Cookie> cookieList = new ArrayList<>(rawCookies.length);
for(String rawCookie : rawCookies) {
rawCookie = rawCookie.replace(" ", "");
final int equalPos = rawCookie.indexOf('=');
if (equalPos == -1) continue;
cookieList.add(new Cookie.Builder()
.name(rawCookie.substring(0, equalPos))
.value(rawCookie.substring(equalPos + 1))
.domain(serverUri.getHost())
.path(
serverUri.getPath().equals("")
? FileUtils.PATH_SEPARATOR
: serverUri.getPath()
)
.build());
}
client.setCookiesForCurrentAccount(cookieList);
}
}
}
@ -279,7 +289,6 @@ public class AccountUtils {
}
}
public static class Constants {
/**
* Version should be 3 numbers separated by dot so it can be parsed by
@ -320,5 +329,4 @@ public class AccountUtils {
public static final String KEY_OAUTH2_REFRESH_TOKEN = "oc_oauth2_refresh_token";
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,48 +24,36 @@
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 java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.auth.AuthState;
import org.apache.commons.httpclient.auth.BasicScheme;
import okhttp3.Credentials;
public class OwnCloudBasicCredentials implements OwnCloudCredentials {
private static final String TAG = OwnCloudCredentials.class.getSimpleName();
private String mUsername;
private String mPassword;
private boolean mAuthenticationPreemptive;
public OwnCloudBasicCredentials(String username, String password) {
mUsername = username != null ? username : "";
mPassword = password != null ? password : "";
mAuthenticationPreemptive = true;
}
public OwnCloudBasicCredentials(String username, String password, boolean preemptiveMode) {
mUsername = username != null ? username : "";
mPassword = password != null ? password : "";
mAuthenticationPreemptive = preemptiveMode;
}
@Override
public void applyTo(OwnCloudClient client) {
AuthPolicy.registerAuthScheme(AuthState.PREEMPTIVE_AUTH_SCHEME, BasicScheme.class);
// Clear previous basic credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
List<String> authPrefs = new ArrayList<String>(1);
authPrefs.add(AuthPolicy.BASIC);
client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
client.getParams().setAuthenticationPreemptive(mAuthenticationPreemptive);
client.getParams().setCredentialCharset(OwnCloudCredentialsFactory.CREDENTIAL_CHARSET);
client.getState().setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(mUsername, mPassword)
);
HttpClient.addHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER,
Credentials.basic(mUsername, mPassword));
}
@Override
@ -87,5 +75,4 @@ public class OwnCloudBasicCredentials implements OwnCloudCredentials {
public boolean authTokenCanBeRefreshed() {
return false;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -23,16 +23,9 @@
*/
package com.owncloud.android.lib.common.authentication;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.auth.AuthState;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.oauth.BearerAuthScheme;
import com.owncloud.android.lib.common.authentication.oauth.BearerCredentials;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
public class OwnCloudBearerCredentials implements OwnCloudCredentials {
@ -46,19 +39,12 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials {
@Override
public void applyTo(OwnCloudClient client) {
AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
AuthPolicy.registerAuthScheme(AuthState.PREEMPTIVE_AUTH_SCHEME, BearerAuthScheme.class);
// Clear previous credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
List<String> authPrefs = new ArrayList<>(1);
authPrefs.add(BearerAuthScheme.AUTH_POLICY);
client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
client.getParams().setAuthenticationPreemptive(true); // true enforces BASIC AUTH ; library is stupid
client.getParams().setCredentialCharset(OwnCloudCredentialsFactory.CREDENTIAL_CHARSET);
client.getState().setCredentials(
AuthScope.ANY,
new BearerCredentials(mAccessToken)
);
HttpClient.addHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER,
HttpConstants.BEARER_AUTHORIZATION_KEY + mAccessToken);
}
@Override
@ -81,5 +67,4 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials {
public boolean authTokenCanBeRefreshed() {
return true;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -25,6 +25,8 @@
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;
public class OwnCloudCredentialsFactory {
@ -64,8 +66,9 @@ public class OwnCloudCredentialsFactory {
@Override
public void applyTo(OwnCloudClient client) {
client.getState().clearCredentials();
client.getState().clearCookies();
// Clear previous basic credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
}
@Override
@ -89,5 +92,4 @@ public class OwnCloudCredentialsFactory {
return null;
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -23,12 +23,9 @@
*/
package com.owncloud.android.lib.common.authentication;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
@ -42,28 +39,12 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
@Override
public void applyTo(OwnCloudClient client) {
client.getParams().setAuthenticationPreemptive(false);
client.getParams().setCredentialCharset(OwnCloudCredentialsFactory.CREDENTIAL_CHARSET);
client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
// Clear previous credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
HttpClient.addHeaderForAllRequests(HttpConstants.COOKIE_HEADER, mSessionCookie);
client.setFollowRedirects(false);
Uri serverUri = client.getBaseUri();
String[] cookies = mSessionCookie.split(";");
if (cookies.length > 0) {
Cookie cookie = null;
for (int i = 0; i < cookies.length; i++) {
int equalPos = cookies[i].indexOf('=');
if (equalPos >= 0) {
cookie = new Cookie();
cookie.setName(cookies[i].substring(0, equalPos));
cookie.setValue(cookies[i].substring(equalPos + 1));
cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT
cookie.setPath(serverUri.getPath()); // VERY IMPORTANT
client.getState().addCookie(cookie);
}
}
}
}
@Override
@ -86,5 +67,4 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
public boolean authTokenCanBeRefreshed() {
return false;
}
}

View File

@ -1,262 +0,0 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import java.util.Map;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.auth.AuthChallengeParser;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.commons.httpclient.auth.InvalidCredentialsException;
import org.apache.commons.httpclient.auth.MalformedChallengeException;
/**
* Bearer authentication scheme as defined in RFC 6750.
*
* @author David A. Velasco
*/
public class BearerAuthScheme implements AuthScheme /*extends RFC2617Scheme*/ {
private static final String TAG = BearerAuthScheme.class.getSimpleName();
public static final String AUTH_POLICY = "Bearer";
/** Whether the bearer authentication process is complete */
private boolean mComplete;
/** Authentication parameter map */
@SuppressWarnings("rawtypes")
private Map mParams = null;
/**
* Default constructor for the bearer authentication scheme.
*/
public BearerAuthScheme() {
mComplete = false;
}
/**
* Constructor for the basic authentication scheme.
*
* @param challenge Authentication challenge
*
* @throws MalformedChallengeException Thrown if the authentication challenge is malformed
*/
public BearerAuthScheme(final String challenge) throws MalformedChallengeException {
processChallenge(challenge);
mComplete = true;
}
/**
* Returns textual designation of the bearer authentication scheme.
*
* @return "Bearer"
*/
public String getSchemeName() {
return "bearer";
}
/**
* Processes the Bearer challenge.
*
* @param challenge The challenge string
*
* @throws MalformedChallengeException Thrown if the authentication challenge is malformed
*/
public void processChallenge(String challenge) throws MalformedChallengeException {
String s = AuthChallengeParser.extractScheme(challenge);
if (!s.equalsIgnoreCase(getSchemeName())) {
throw new MalformedChallengeException(
"Invalid " + getSchemeName() + " challenge: " + challenge);
}
mParams = AuthChallengeParser.extractParams(challenge);
mComplete = true;
}
/**
* Tests if the Bearer authentication process has been completed.
*
* @return 'true' if Bearer authorization has been processed, 'false' otherwise.
*/
public boolean isComplete() {
return this.mComplete;
}
/**
* Produces bearer authorization string for the given set of
* {@link Credentials}.
*
* @param credentials The set of credentials to be used for authentication
* @param method Method name is ignored by the bearer authentication scheme
* @param uri URI is ignored by the bearer authentication scheme
* @throws InvalidCredentialsException If authentication credentials are not valid or not applicable
* for this authentication scheme
* @throws AuthenticationException If authorization string cannot be generated due to an authentication failure
* @return A bearer authorization string
*/
public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
BearerCredentials bearer;
try {
bearer = (BearerCredentials) credentials;
} catch (ClassCastException e) {
throw new InvalidCredentialsException(
"Credentials cannot be used for bearer authentication: "
+ credentials.getClass().getName());
}
return BearerAuthScheme.authenticate(bearer);
}
/**
* Returns 'false'. Bearer authentication scheme is request based.
*
* @return 'false'.
*/
public boolean isConnectionBased() {
return false;
}
/**
* Produces bearer authorization string for the given set of {@link Credentials}.
*
* @param credentials The set of credentials to be used for authentication
* @param method The method being authenticated
* @throws InvalidCredentialsException If authentication credentials are not valid or not applicable for this authentication
* scheme.
* @throws AuthenticationException If authorization string cannot be generated due to an authentication failure.
*
* @return a basic authorization string
*/
public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
if (method == null) {
throw new IllegalArgumentException("Method may not be null");
}
BearerCredentials bearer = null;
try {
bearer = (BearerCredentials) credentials;
} catch (ClassCastException e) {
throw new InvalidCredentialsException(
"Credentials cannot be used for bearer authentication: "
+ credentials.getClass().getName());
}
return BearerAuthScheme.authenticate(
bearer,
method.getParams().getCredentialCharset());
}
/**
* Returns a bearer Authorization header value for the given
* {@link BearerCredentials}.
*
* @param credentials The credentials to encode.
*
* @return A bearer authorization string
*/
public static String authenticate(BearerCredentials credentials) {
return authenticate(credentials, "ISO-8859-1");
}
/**
* Returns a bearer Authorization header value for the given
* {@link BearerCredentials} and charset.
*
* @param credentials The credentials to encode.
* @param charset The charset to use for encoding the credentials
*
* @return A bearer authorization string
*
* @since 3.0
*/
public static String authenticate(BearerCredentials credentials, String charset) {
if (credentials == null) {
throw new IllegalArgumentException("Credentials may not be null");
}
if (charset == null || charset.length() == 0) {
throw new IllegalArgumentException("charset may not be null or empty");
}
StringBuffer buffer = new StringBuffer();
buffer.append(credentials.getAccessToken());
return "Bearer " + buffer.toString();
}
/**
* Returns a String identifying the authentication challenge. This is
* used, in combination with the host and port to determine if
* authorization has already been attempted or not. Schemes which
* require multiple requests to complete the authentication should
* return a different value for each stage in the request.
*
* Additionally, the ID should take into account any changes to the
* authentication challenge and return a different value when appropriate.
* For example when the realm changes in basic authentication it should be
* considered a different authentication attempt and a different value should
* be returned.
*
* This method simply returns the realm for the challenge.
*
* @return String a String identifying the authentication challenge.
*/
@Override
public String getID() {
return getRealm();
}
/**
* Returns authentication parameter with the given name, if available.
*
* @param name The name of the parameter to be returned
*
* @return The parameter with the given name
*/
@Override
public String getParameter(String name) {
if (name == null) {
throw new IllegalArgumentException("Parameter name may not be null");
}
if (mParams == null) {
return null;
}
return (String) mParams.get(name.toLowerCase());
}
/**
* Returns authentication realm. The realm may not be null.
*
* @return The authentication realm
*/
@Override
public String getRealm() {
return getParameter("realm");
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,16 +24,14 @@
package com.owncloud.android.lib.common.authentication.oauth;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.util.LangUtils;
/**
* Bearer token {@link Credentials}
*
* @author David A. Velasco
* @author Christian Schabesberger
*/
public class BearerCredentials implements Credentials {
public class BearerCredentials {
public static final int HASH_SEED = 17;
public static final int HASH_OFFSET = 37;
private String mAccessToken;
@ -76,9 +74,7 @@ public class BearerCredentials implements Credentials {
* @return The hash code of the access token
*/
public int hashCode() {
int hash = LangUtils.HASH_SEED;
hash = LangUtils.hashCode(hash, mAccessToken);
return hash;
return HASH_SEED * HASH_OFFSET + mAccessToken.hashCode();
}
/**
@ -93,12 +89,10 @@ public class BearerCredentials implements Credentials {
if (this == o) return true;
if (this.getClass().equals(o.getClass())) {
BearerCredentials that = (BearerCredentials) o;
if (LangUtils.equals(mAccessToken, that.mAccessToken)) {
if (mAccessToken.equals(that.mAccessToken)) {
return true;
}
}
return false;
}
}

View File

@ -1,7 +1,8 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
* @author Christian Schabesberger
* 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
@ -31,21 +32,21 @@ 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.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 org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.net.URL;
import java.util.Map;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class OAuth2GetAccessTokenOperation extends RemoteOperation {
public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private String mGrantType;
private String mCode;
@ -82,29 +83,33 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation {
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
PostMethod postMethod = null;
RemoteOperationResult<Map<String, String>> result = null;
try {
NameValuePair[] nameValuePairs = new NameValuePair[4];
nameValuePairs[0] = new NameValuePair(OAuth2Constants.KEY_GRANT_TYPE, mGrantType);
nameValuePairs[1] = new NameValuePair(OAuth2Constants.KEY_CODE, mCode);
nameValuePairs[2] = new NameValuePair(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri);
nameValuePairs[3] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId);
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE, mGrantType)
.addFormDataPart(OAuth2Constants.KEY_CODE, mCode)
.addFormDataPart(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri)
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.build();
Uri.Builder uriBuilder = client.getBaseUri().buildUpon();
uriBuilder.appendEncodedPath(mAccessTokenEndpointPath);
postMethod = new PostMethod(uriBuilder.build().toString());
postMethod.setRequestBody(nameValuePairs);
final PostMethod postMethod = new PostMethod(new URL(
client.getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString()));
OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(
mClientId,
mClientSecret
);
postMethod.setRequestBody(requestBody);
OwnCloudCredentials oauthCredentials =
new OwnCloudBasicCredentials(mClientId, mClientSecret);
OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeMethod(postMethod);
client.executeHttpMethod(postMethod);
switchClientCredentials(oldCredentials);
String response = postMethod.getResponseBodyAsString();
@ -114,28 +119,22 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation {
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
result = new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR);
} else {
result = new RemoteOperationResult(true, postMethod);
ArrayList<Object> data = new ArrayList<>();
data.add(accessTokenResult);
result.setData(data);
result = new RemoteOperationResult<>(ResultCode.OK);
result.setData(accessTokenResult);
}
} else {
result = new RemoteOperationResult(false, postMethod);
result = new RemoteOperationResult<>(ResultCode.OK);
client.exhaustResponse(postMethod.getResponseBodyAsStream());
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
} finally {
if (postMethod != null)
postMethod.releaseConnection(); // let the connection available for other methods
}
return result;
}
@ -144,5 +143,4 @@ public class OAuth2GetAccessTokenOperation extends RemoteOperation {
getClient().setCredentials(newCredentials);
return previousCredentials;
}
}

View File

@ -2,8 +2,9 @@
* ownCloud Android client application
*
* @author David González Verdugo
* @author Christian Schabesberger
*
* Copyright (C) 2017 ownCloud GmbH.
* 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,
@ -26,19 +27,22 @@ 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.OwnCloudCredentials;
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 com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONObject;
import java.util.ArrayList;
import java.net.URL;
import java.util.Map;
public class OAuth2RefreshAccessTokenOperation extends RemoteOperation {
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();
@ -71,70 +75,55 @@ public class OAuth2RefreshAccessTokenOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
PostMethod postMethod = null;
protected RemoteOperationResult<Map<String, String>> run(OwnCloudClient client) {
try {
NameValuePair[] nameValuePairs = new NameValuePair[3];
nameValuePairs[0] = new NameValuePair(
OAuth2Constants.KEY_GRANT_TYPE,
OAuth2GrantType.REFRESH_TOKEN.getValue() // always for this operation
);
nameValuePairs[1] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId);
nameValuePairs[2] = new NameValuePair(OAuth2Constants.KEY_REFRESH_TOKEN, mRefreshToken);
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE,
OAuth2GrantType.REFRESH_TOKEN.getValue())
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.addFormDataPart(OAuth2Constants.KEY_REFRESH_TOKEN, mRefreshToken)
.build();
Uri.Builder uriBuilder = client.getBaseUri().buildUpon();
uriBuilder.appendEncodedPath(mAccessTokenEndpointPath);
postMethod = new PostMethod(uriBuilder.build().toString());
postMethod.setRequestBody(nameValuePairs);
final PostMethod postMethod = new PostMethod(new URL(
client.getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString()));
postMethod.setRequestBody(requestBody);
OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(
mClientId,
mClientSecret
);
OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeMethod(postMethod);
final OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(mClientId, mClientSecret);
final OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeHttpMethod(postMethod);
switchClientCredentials(oldCredentials);
String response = postMethod.getResponseBodyAsString();
Log_OC.d(TAG, "OAUTH2: raw response from POST TOKEN: " + response);
final String responseData = postMethod.getResponseBodyAsString();
Log_OC.d(TAG, "OAUTH2: raw response from POST TOKEN: " + responseData);
if (response != null && response.length() > 0) {
JSONObject tokenJson = new JSONObject(response);
Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
if (responseData != null && responseData.length() > 0) {
final JSONObject tokenJson = new JSONObject(responseData);
} else {
result = new RemoteOperationResult(true, postMethod);
ArrayList<Object> data = new ArrayList<>();
data.add(accessTokenResult);
result.setData(data);
}
final Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
final RemoteOperationResult<Map<String, String>> result = new RemoteOperationResult<>(ResultCode.OK);
result.setData(accessTokenResult);
return (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null)
? new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR)
: result;
} else {
result = new RemoteOperationResult(false, postMethod);
client.exhaustResponse(postMethod.getResponseBodyAsStream());
return new RemoteOperationResult<>(postMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
} finally {
if (postMethod != null) {
postMethod.releaseConnection(); // let the connection available for other methods
}
return new RemoteOperationResult<>(e);
}
return result;
}
private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) {
@ -142,5 +131,4 @@ public class OAuth2RefreshAccessTokenOperation extends RemoteOperation {
getClient().setCredentials(newCredentials);
return previousCredentials;
}
}

View File

@ -0,0 +1,172 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http;
import android.content.Context;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.http.interceptors.HttpInterceptor;
import com.owncloud.android.lib.common.http.interceptors.RequestHeaderInterceptor;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
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 {
private static final String TAG = HttpClient.class.toString();
private static OkHttpClient sOkHttpClient;
private static HttpInterceptor sOkHttpInterceptor;
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);
// Automatic cookie handling, NOT PERSISTENT
CookieJar cookieJar = new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// Avoid duplicated cookies
Set<Cookie> nonDuplicatedCookiesSet = new HashSet<>();
nonDuplicatedCookiesSet.addAll(cookies);
List<Cookie> nonDuplicatedCookiesList = new ArrayList<>();
nonDuplicatedCookiesList.addAll(nonDuplicatedCookiesSet);
sCookieStore.put(url.host(), nonDuplicatedCookiesList);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = sCookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<>();
}
};
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.addInterceptor(getOkHttpInterceptor())
.protocols(Arrays.asList(Protocol.HTTP_1_1))
.readTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
.connectTimeout(HttpConstants.DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.followRedirects(false)
.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());
sOkHttpClient = clientBuilder.build();
} catch (Exception e) {
Log_OC.e(TAG, "Could not setup SSL system.", e);
}
}
return sOkHttpClient;
}
private static HttpInterceptor getOkHttpInterceptor() {
if (sOkHttpInterceptor == null) {
sOkHttpInterceptor = new HttpInterceptor();
addHeaderForAllRequests(HttpConstants.USER_AGENT_HEADER, OwnCloudClientManagerFactory.getUserAgent());
addHeaderForAllRequests(HttpConstants.PARAM_SINGLE_COOKIE_HEADER, "true");
addHeaderForAllRequests(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
}
return sOkHttpInterceptor;
}
public void disableAutomaticCookiesHandling() {
OkHttpClient.Builder clientBuilder = getOkHttpClient().newBuilder();
clientBuilder.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// DO NOTHING
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
return new ArrayList<>();
}
});
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());
}
public void clearCookies() {
sCookieStore.clear();
}
}

View File

@ -0,0 +1,189 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http;
/**
* @author David González Verdugo
*/
public class HttpConstants {
/***********************************************************************************************************
*************************************************** HEADERS ***********************************************
***********************************************************************************************************/
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String COOKIE_HEADER = "Cookie";
public static final String BEARER_AUTHORIZATION_KEY = "Bearer ";
public static final String USER_AGENT_HEADER = "User-Agent";
public static final String IF_MATCH_HEADER = "If-Match";
public static final String IF_NONE_MATCH_HEADER = "If-None-Match";
public static final String CONTENT_TYPE_HEADER = "Content-Type";
public static final String CONTENT_LENGTH_HEADER = "Content-Length";
public static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
public static final String OC_X_OC_MTIME_HEADER = "X-OC-Mtime";
public static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
public static final String OC_X_REQUEST_ID = "X-Request-ID";
public static final String LOCATION_HEADER = "Location";
public static final String LOCATION_HEADER_LOWER = "location";
public static final String CONTENT_TYPE_URLENCODED_UTF8 = "application/x-www-form-urlencoded; charset=utf-8";
public static final String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
public static final String ACCEPT_ENCODING_IDENTITY = "identity";
/***********************************************************************************************************
************************************************ STATUS CODES *********************************************
***********************************************************************************************************/
/**
* 1xx Informational
*/
// 100 Continue (HTTP/1.1 - RFC 2616)
public static final int HTTP_CONTINUE = 100;
// 101 Switching Protocols (HTTP/1.1 - RFC 2616)
public static final int HTTP_SWITCHING_PROTOCOLS = 101;
// 102 Processing (WebDAV - RFC 2518)
public static final int HTTP_PROCESSING = 102;
/**
* 2xx Success
*/
// 200 OK (HTTP/1.0 - RFC 1945)
public static final int HTTP_OK = 200;
// 201 Created (HTTP/1.0 - RFC 1945)
public static final int HTTP_CREATED = 201;
// 202 Accepted (HTTP/1.0 - RFC 1945)
public static final int HTTP_ACCEPTED = 202;
// 203 Non Authoritative Information (HTTP/1.1 - RFC 2616)
public static final int HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
// 204 No Content</tt> (HTTP/1.0 - RFC 1945)
public static final int HTTP_NO_CONTENT = 204;
// 205 Reset Content</tt> (HTTP/1.1 - RFC 2616)
public static final int HTTP_RESET_CONTENT = 205;
// 206 Partial Content</tt> (HTTP/1.1 - RFC 2616)
public static final int HTTP_PARTIAL_CONTENT = 206;
//207 Multi-Status (WebDAV - RFC 2518) or 207 Partial Update OK (HTTP/1.1 - draft-ietf-http-v11-spec-rev-01?)
public static final int HTTP_MULTI_STATUS = 207;
/**
* 3xx Redirection
*/
// 300 Mutliple Choices</tt> (HTTP/1.1 - RFC 2616)
public static final int HTTP_MULTIPLE_CHOICES = 300;
// 301 Moved Permanently</tt> (HTTP/1.0 - RFC 1945)
public static final int HTTP_MOVED_PERMANENTLY = 301;
// 302 Moved Temporarily</tt> (Sometimes <tt>Found) (HTTP/1.0 - RFC 1945)
public static final int HTTP_MOVED_TEMPORARILY = 302;
// 303 See Other (HTTP/1.1 - RFC 2616)
public static final int HTTP_SEE_OTHER = 303;
// 304 Not Modified (HTTP/1.0 - RFC 1945)
public static final int HTTP_NOT_MODIFIED = 304;
// 305 Use Proxy (HTTP/1.1 - RFC 2616)
public static final int HTTP_USE_PROXY = 305;
// 307 Temporary Redirect (HTTP/1.1 - RFC 2616)
public static final int HTTP_TEMPORARY_REDIRECT = 307;
/**
* 4xx Client Error
*/
// 400 Bad Request (HTTP/1.1 - RFC 2616)
public static final int HTTP_BAD_REQUEST = 400;
// 401 Unauthorized (HTTP/1.0 - RFC 1945)
public static final int HTTP_UNAUTHORIZED = 401;
// 402 Payment Required (HTTP/1.1 - RFC 2616)
public static final int HTTP_PAYMENT_REQUIRED = 402;
// 403 Forbidden (HTTP/1.0 - RFC 1945)
public static final int HTTP_FORBIDDEN = 403;
// 404 Not Found (HTTP/1.0 - RFC 1945)
public static final int HTTP_NOT_FOUND = 404;
// 405 Method Not Allowed (HTTP/1.1 - RFC 2616)
public static final int HTTP_METHOD_NOT_ALLOWED = 405;
// 406 Not Acceptable (HTTP/1.1 - RFC 2616)
public static final int HTTP_NOT_ACCEPTABLE = 406;
// 407 Proxy Authentication Required (HTTP/1.1 - RFC 2616)
public static final int HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
// 408 Request Timeout (HTTP/1.1 - RFC 2616)
public static final int HTTP_REQUEST_TIMEOUT = 408;
// 409 Conflict (HTTP/1.1 - RFC 2616)
public static final int HTTP_CONFLICT = 409;
// 410 Gone (HTTP/1.1 - RFC 2616)
public static final int HTTP_GONE = 410;
// 411 Length Required (HTTP/1.1 - RFC 2616)
public static final int HTTP_LENGTH_REQUIRED = 411;
// 412 Precondition Failed (HTTP/1.1 - RFC 2616)
public static final int HTTP_PRECONDITION_FAILED = 412;
// 413 Request Entity Too Large (HTTP/1.1 - RFC 2616)
public static final int HTTP_REQUEST_TOO_LONG = 413;
// 414 Request-URI Too Long (HTTP/1.1 - RFC 2616)
public static final int HTTP_REQUEST_URI_TOO_LONG = 414;
// 415 Unsupported Media Type (HTTP/1.1 - RFC 2616)
public static final int HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
// 416 Requested Range Not Satisfiable (HTTP/1.1 - RFC 2616)
public static final int HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
// 417 Expectation Failed (HTTP/1.1 - RFC 2616)
public static final int HTTP_EXPECTATION_FAILED = 417;
// 419 Insufficient Space on Resource (WebDAV - draft-ietf-webdav-protocol-05?)
// or <tt>419 Proxy Reauthentication Required (HTTP/1.1 drafts?)
public static final int HTTP_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
// 420 Method Failure (WebDAV - draft-ietf-webdav-protocol-05?)
public static final int HTTP_METHOD_FAILURE = 420;
// 422 Unprocessable Entity (WebDAV - RFC 2518)
public static final int HTTP_UNPROCESSABLE_ENTITY = 422;
// 423 Locked (WebDAV - RFC 2518)
public static final int HTTP_LOCKED = 423;
// 424 Failed Dependency (WebDAV - RFC 2518)
public static final int HTTP_FAILED_DEPENDENCY = 424;
/**
* 5xx Client Error
*/
// 500 Server Error (HTTP/1.0 - RFC 1945)
public static final int HTTP_INTERNAL_SERVER_ERROR = 500;
// 501 Not Implemented (HTTP/1.0 - RFC 1945)
public static final int HTTP_NOT_IMPLEMENTED = 501;
// 502 Bad Gateway (HTTP/1.0 - RFC 1945)
public static final int HTTP_BAD_GATEWAY = 502;
// 503 Service Unavailable (HTTP/1.0 - RFC 1945)
public static final int HTTP_SERVICE_UNAVAILABLE = 503;
// 504 Gateway Timeout (HTTP/1.1 - RFC 2616)
public static final int HTTP_GATEWAY_TIMEOUT = 504;
// 505 HTTP Version Not Supported (HTTP/1.1 - RFC 2616)
public static final int HTTP_HTTP_VERSION_NOT_SUPPORTED = 505;
// 507 Insufficient Storage (WebDAV - RFC 2518)
public static final int HTTP_INSUFFICIENT_STORAGE = 507;
/***********************************************************************************************************
*************************************************** TIMEOUTS **********************************************
***********************************************************************************************************/
/** 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;
}

View File

@ -0,0 +1,109 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.interceptors;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* Http interceptor to use multiple interceptors in the same {@link okhttp3.OkHttpClient} instance
* @author David González Verdugo
*/
public class HttpInterceptor implements Interceptor {
private final ArrayList<RequestInterceptor> mRequestInterceptors = new ArrayList<>();
private final ArrayList<ResponseInterceptor> mResponseInterceptors = new ArrayList<>();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
for (RequestInterceptor interceptor : mRequestInterceptors) {
request = interceptor.intercept(request);
}
Response response = chain.proceed(request);
for (ResponseInterceptor interceptor : mResponseInterceptors) {
response = interceptor.intercept(response);
}
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) {
mResponseInterceptors.add(responseInterceptor);
return this;
}
public ArrayList<RequestInterceptor> getRequestInterceptors() {
return mRequestInterceptors;
}
private ArrayList<RequestHeaderInterceptor> getRequestHeaderInterceptors() {
ArrayList<RequestHeaderInterceptor> requestHeaderInterceptors = new ArrayList<>();
for (RequestInterceptor requestInterceptor : mRequestInterceptors) {
if (requestInterceptor instanceof RequestHeaderInterceptor) {
requestHeaderInterceptors.add((RequestHeaderInterceptor) requestInterceptor);
}
}
return requestHeaderInterceptors;
}
public void deleteRequestHeaderInterceptor(String headerName) {
Iterator<RequestInterceptor> requestInterceptorIterator = mRequestInterceptors.iterator();
while (requestInterceptorIterator.hasNext()) {
RequestInterceptor currentRequestInterceptor = requestInterceptorIterator.next();
if (currentRequestInterceptor instanceof RequestHeaderInterceptor &&
((RequestHeaderInterceptor) currentRequestInterceptor).getHeaderName().equals(headerName)) {
requestInterceptorIterator.remove();
}
}
}
public ArrayList<ResponseInterceptor> getResponseInterceptors() {
return mResponseInterceptors;
}
}

View File

@ -0,0 +1,54 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.interceptors;
import okhttp3.Request;
/**
* Intercept requests to update their headers
*/
public class RequestHeaderInterceptor implements HttpInterceptor.RequestInterceptor {
private String mHeaderName;
private String mHeaderValue;
public RequestHeaderInterceptor(String headerName, String headerValue) {
this.mHeaderName = headerName;
this.mHeaderValue = headerValue;
}
@Override
public Request intercept(Request request) {
return request.newBuilder().addHeader(mHeaderName, mHeaderValue).build();
}
public String getHeaderName() {
return mHeaderName;
}
public String getHeaderValue() {
return mHeaderValue;
}
}

View File

@ -0,0 +1,192 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.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;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Wrapper to perform http calls transparently by using:
* - OkHttp for non webdav methods
* - Dav4Android for webdav methods
*
* @author David González Verdugo
*/
public abstract class HttpBaseMethod {
protected OkHttpClient mOkHttpClient;
protected Request mRequest;
protected RequestBody mRequestBody;
protected Response mResponse;
protected String mResponseBodyString;
protected Call mCall;
protected HttpBaseMethod(URL url) {
mOkHttpClient = HttpClient.getOkHttpClient();
mRequest = new Request.Builder()
.url(HttpUrl.parse(url.toString()))
.build();
}
public int execute() throws Exception {
return onExecute();
}
public void abort() {
mCall.cancel();
}
public boolean isAborted() {
return mCall.isCanceled();
}
//////////////////////////////
// For override
//////////////////////////////
protected abstract int onExecute() throws Exception;
//////////////////////////////
// Getter
//////////////////////////////
// Request
public Headers getRequestHeaders() {
return mRequest.headers();
}
public String getRequestHeader(String name) {
return mRequest.header(name);
}
// Response
public int getStatusCode() {
return mResponse.code();
}
public String getStatusMessage() {
return mResponse.message();
}
public String getResponseBodyAsString() throws IOException {
if (mResponseBodyString == null && mResponse.body() != null) {
mResponseBodyString = mResponse.body().string();
}
return mResponseBodyString;
}
public InputStream getResponseBodyAsStream() {
if (mResponse.body() != null) {
return mResponse.body().byteStream();
}
return null;
}
public Headers getResponseHeaders() {
return mResponse.headers();
}
public String getResponseHeader(String headerName) {
return mResponse.header(headerName);
}
public boolean getRetryOnConnectionFailure() {
return mOkHttpClient.retryOnConnectionFailure();
}
//////////////////////////////
// Setter
//////////////////////////////
// Connection parameters
public void setReadTimeout(long readTimeout, TimeUnit timeUnit) {
mOkHttpClient = mOkHttpClient.newBuilder()
.readTimeout(readTimeout, timeUnit)
.build();
}
public void setConnectionTimeout(long connectionTimeout, TimeUnit timeUnit) {
mOkHttpClient = mOkHttpClient.newBuilder()
.readTimeout(connectionTimeout, timeUnit)
.build();
}
public void setFollowRedirects(boolean followRedirects) {
mOkHttpClient = mOkHttpClient.newBuilder()
.followRedirects(followRedirects)
.build();
}
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
mOkHttpClient = mOkHttpClient.newBuilder()
.retryOnConnectionFailure(retryOnConnectionFailure)
.build();
}
// Request
public void addRequestHeader(String name, String value) {
mRequest = mRequest.newBuilder()
.addHeader(name, value)
.build();
}
/**
* Sets a header and replace it if already exists with that name
*
* @param name header name
* @param value header value
*/
public void setRequestHeader(String name, String value) {
mRequest = mRequest.newBuilder()
.header(name, value)
.build();
}
public void setRequestBody(RequestBody requestBody) {
mRequestBody = requestBody;
}
public void setUrl(HttpUrl url) {
mRequest = mRequest.newBuilder()
.url(url)
.build();
}
}

View File

@ -0,0 +1,50 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.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 DeleteMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
.delete()
.build();
return super.onExecute();
}
}

View File

@ -0,0 +1,50 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.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 {
public GetMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
.get()
.build();
return super.onExecute();
}
}

View File

@ -0,0 +1,52 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav;
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
*
* @author David González Verdugo
*/
public abstract class HttpMethod extends HttpBaseMethod {
public HttpMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mCall = mOkHttpClient.newCall(mRequest);
mResponse = mCall.execute();
return super.getStatusCode();
}
}

View File

@ -0,0 +1,50 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.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){
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
.post(mRequestBody)
.build();
return super.onExecute();
}
}

View File

@ -0,0 +1,46 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.HttpUrl;
public class PutMethod extends HttpMethod{
public PutMethod(URL url){
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
.put(mRequestBody)
.build();
return super.onExecute();
}
}

View File

@ -0,0 +1,56 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import java.net.URL;
import kotlin.Unit;
/**
* Copy calls wrapper
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class CopyMethod extends DavMethod {
final String destinationUrl;
final boolean forceOverride;
public CopyMethod(URL url, String destinationUrl, boolean forceOverride) {
super(url);
this.destinationUrl = destinationUrl;
this.forceOverride = forceOverride;
}
@Override
public int onExecute() throws Exception {
mDavResource.copy(destinationUrl, forceOverride, response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
}
}

View File

@ -0,0 +1,33 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
/**
* @author David González Verdugo
*/
public class DavConstants {
public static final int DEPTH_0 = 0;
public static final int DEPTH_1 = 1;
}

View File

@ -0,0 +1,158 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.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 okhttp3.HttpUrl;
import okhttp3.Protocol;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* Wrapper to perform WebDAV (dav4android) calls
* @author David González Verdugo
*/
public abstract class DavMethod extends HttpBaseMethod {
protected DavOCResource mDavResource;
protected DavMethod(URL url) {
super(url);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(url.toString()),
Constants.INSTANCE.getLog());
}
@Override
public void abort() {
mDavResource.cancelCall();
}
@Override
public int execute() throws Exception {
try {
return onExecute();
} catch (HttpException httpException) {
// Modify responses with information gathered from exceptions
if (httpException instanceof RedirectException) {
mResponse = new Response.Builder()
.header(
HttpConstants.LOCATION_HEADER, ((RedirectException) httpException).getRedirectLocation()
)
.code(httpException.getCode())
.request(mRequest)
.message(httpException.getMessage())
.protocol(Protocol.HTTP_1_1)
.build();
} else if (mResponse != null) {
ResponseBody responseBody = ResponseBody.create(
mResponse.body().contentType(),
httpException.getResponseBody()
);
mResponse = mResponse.newBuilder()
.body(responseBody)
.build();
}
return httpException.getCode();
}
}
//////////////////////////////
// Setter
//////////////////////////////
// Connection parameters
@Override
public void setReadTimeout(long readTimeout, TimeUnit timeUnit) {
super.setReadTimeout(readTimeout, timeUnit);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public void setConnectionTimeout(long connectionTimeout, TimeUnit timeUnit) {
super.setConnectionTimeout(connectionTimeout, timeUnit);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public void setFollowRedirects(boolean followRedirects) {
super.setFollowRedirects(followRedirects);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
super.setRetryOnConnectionFailure(retryOnConnectionFailure);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
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();
}
}

View File

@ -0,0 +1,15 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyUtils;
public class DavUtils {
public static final Property.Name[] getAllPropset() {
return PropertyUtils.INSTANCE.getAllPropSet();
}
public static final Property.Name[] getQuotaPropSet() {
return PropertyUtils.INSTANCE.getQuotaPropset();
}
}

View File

@ -0,0 +1,50 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import java.net.URL;
import kotlin.Unit;
/**
* MkCol calls wrapper
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class MkColMethod extends DavMethod {
public MkColMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws Exception {
mDavResource.mkCol(null, response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
}
}

View File

@ -0,0 +1,61 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import com.owncloud.android.lib.common.http.HttpConstants;
import java.net.URL;
import kotlin.Unit;
/**
* Move calls wrapper
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class MoveMethod extends DavMethod {
final String destinationUrl;
final boolean forceOverride;
public MoveMethod(URL url, String destinationUrl, boolean forceOverride) {
super(url);
this.destinationUrl = destinationUrl;
this.forceOverride = forceOverride;
}
@Override
public int onExecute() throws Exception {
mDavResource.move(
destinationUrl,
forceOverride,
super.getRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER),
super.getRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER), response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
}
}

View File

@ -0,0 +1,93 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.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;
/**
* Propfind calls wrapper
* @author David González Verdugo
*/
public class PropfindMethod extends DavMethod {
// request
private final int mDepth;
private final Property.Name[] mPropertiesToRequest;
// response
private final List<Response> mMembers;
private Response mRoot;
public PropfindMethod(URL url, int depth, Property.Name[] propertiesToRequest) {
super(url);
mDepth = depth;
mPropertiesToRequest = propertiesToRequest;
mMembers = new ArrayList<>();
mRoot = null;
}
@Override
public int onExecute() throws IOException, DavException{
mDavResource.propfind(mDepth, mPropertiesToRequest,
(Response response, Response.HrefRelation hrefRelation) -> {
switch (hrefRelation) {
case MEMBER:
mMembers.add(response);
break;
case SELF:
mRoot = response;
break;
case OTHER:
default:
}
return Unit.INSTANCE;
}, response -> {
mResponse = response;
return Unit.INSTANCE;
});
return getStatusCode();
}
public int getDepth() {
return mDepth;
}
public List<Response> getMembers() {
return mMembers;
}
public Response getRoot() {
return mRoot;
}
}

View File

@ -0,0 +1,59 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import com.owncloud.android.lib.common.http.HttpConstants;
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 {
mDavResource.put(
mRequestBody,
super.getRequestHeader(HttpConstants.IF_MATCH_HEADER),
super.getRequestHeader(HttpConstants.CONTENT_TYPE_HEADER),
super.getRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER),
super.getRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER), response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
}
}

View File

@ -1,344 +0,0 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with
* a custom SSLContext and an optional Hostname Verifier.
*
* @author David A. Velasco
*/
public class AdvancedSslSocketFactory implements SecureProtocolSocketFactory {
private static final String TAG = AdvancedSslSocketFactory.class.getSimpleName();
private SSLContext mSslContext = null;
private AdvancedX509TrustManager mTrustManager = null;
private X509HostnameVerifier mHostnameVerifier = null;
public SSLContext getSslContext() {
return mSslContext;
}
/**
* Constructor for AdvancedSSLProtocolSocketFactory.
*/
public AdvancedSslSocketFactory(
SSLContext sslContext, AdvancedX509TrustManager trustManager, X509HostnameVerifier hostnameVerifier
) {
if (sslContext == null)
throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null SSLContext");
if (trustManager == null && mHostnameVerifier != null)
throw new IllegalArgumentException(
"AdvancedSslSocketFactory can not be created with a null Trust Manager and a " +
"not null Hostname Verifier"
);
mSslContext = sslContext;
mTrustManager = trustManager;
mHostnameVerifier = hostnameVerifier;
}
/**
* @see ProtocolSocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int)
*/
@Override
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
throws IOException, UnknownHostException {
Socket socket = mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
enableSecureProtocols(socket);
verifyPeerIdentity(host, port, socket);
return socket;
}
/*
private void logSslInfo() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
Log_OC.v(TAG, "SUPPORTED SSL PARAMETERS");
logSslParameters(mSslContext.getSupportedSSLParameters());
Log_OC.v(TAG, "DEFAULT SSL PARAMETERS");
logSslParameters(mSslContext.getDefaultSSLParameters());
Log_OC.i(TAG, "CURRENT PARAMETERS");
Log_OC.i(TAG, "Protocol: " + mSslContext.getProtocol());
}
Log_OC.i(TAG, "PROVIDER");
logSecurityProvider(mSslContext.getProvider());
}
private void logSecurityProvider(Provider provider) {
Log_OC.i(TAG, "name: " + provider.getName());
Log_OC.i(TAG, "version: " + provider.getVersion());
Log_OC.i(TAG, "info: " + provider.getInfo());
Enumeration<?> keys = provider.propertyNames();
String key;
while (keys.hasMoreElements()) {
key = (String) keys.nextElement();
Log_OC.i(TAG, " property " + key + " : " + provider.getProperty(key));
}
}
private void logSslParameters(SSLParameters params) {
Log_OC.v(TAG, "Cipher suites: ");
String [] elements = params.getCipherSuites();
for (int i=0; i<elements.length ; i++) {
Log_OC.v(TAG, " " + elements[i]);
}
Log_OC.v(TAG, "Protocols: ");
elements = params.getProtocols();
for (int i=0; i<elements.length ; i++) {
Log_OC.v(TAG, " " + elements[i]);
}
}
*/
/**
* Attempts to get a new socket connection to the given host within the
* given time limit.
*
* @param host the host name/IP
* @param port the port on the host
* @param localAddress the local host name/IP to bind the socket to
* @param localPort the port on the local machine
* @param params {@link HttpConnectionParams Http connection parameters}
* @return Socket a new socket
* @throws IOException if an I/O error occurs while creating the socket
* @throws UnknownHostException if the IP address of the host cannot be
* determined
*/
@Override
public Socket createSocket(final String host, final int port,
final InetAddress localAddress, final int localPort,
final HttpConnectionParams params) throws IOException,
UnknownHostException, ConnectTimeoutException {
Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" +
localPort + ", params: " + params);
if (params == null) {
throw new IllegalArgumentException("Parameters may not be null");
}
int timeout = params.getConnectionTimeout();
//logSslInfo();
SocketFactory socketfactory = mSslContext.getSocketFactory();
Log_OC.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
Socket socket = socketfactory.createSocket();
enableSecureProtocols(socket);
SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
SocketAddress remoteaddr = new InetSocketAddress(host, port);
socket.setSoTimeout(params.getSoTimeout());
WriteTimeoutEnforcer.setSoWriteTimeout(params.getSoTimeout(), socket);
socket.bind(localaddr);
ServerNameIndicator.setServerNameIndication(host, (SSLSocket) socket);
socket.connect(remoteaddr, timeout);
verifyPeerIdentity(host, port, socket);
return socket;
}
/**
* @see ProtocolSocketFactory#createSocket(java.lang.String, int)
*/
@Override
public Socket createSocket(String host, int port) throws IOException,
UnknownHostException {
Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
enableSecureProtocols(socket);
verifyPeerIdentity(host, port, socket);
return socket;
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
UnknownHostException {
Socket sslSocket = mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
enableSecureProtocols(sslSocket);
verifyPeerIdentity(host, port, sslSocket);
return sslSocket;
}
public boolean equals(Object obj) {
return ((obj != null) && obj.getClass().equals(
AdvancedSslSocketFactory.class));
}
public int hashCode() {
return AdvancedSslSocketFactory.class.hashCode();
}
public X509HostnameVerifier getHostNameVerifier() {
return mHostnameVerifier;
}
public void setHostNameVerifier(X509HostnameVerifier hostnameVerifier) {
mHostnameVerifier = hostnameVerifier;
}
/**
* Verifies the identity of the server.
*
* The server certificate is verified first.
*
* Then, the host name is compared with the content of the server certificate using the current host name verifier,
* if any.
*
* @param socket
*/
private void verifyPeerIdentity(String host, int port, Socket socket) throws IOException {
try {
CertificateCombinedException failInHandshake = null;
/// 1. VERIFY THE SERVER CERTIFICATE through the registered TrustManager
/// (that should be an instance of AdvancedX509TrustManager)
try {
SSLSocket sock = (SSLSocket) socket; // a new SSLSession instance is created as a "side effect"
sock.startHandshake();
} catch (RuntimeException e) {
if (e instanceof CertificateCombinedException) {
failInHandshake = (CertificateCombinedException) e;
} else {
Throwable cause = e.getCause();
Throwable previousCause = null;
while (cause != null &&
cause != previousCause &&
!(cause instanceof CertificateCombinedException)) {
previousCause = cause;
cause = cause.getCause();
}
if (cause != null && cause instanceof CertificateCombinedException) {
failInHandshake = (CertificateCombinedException) cause;
}
}
if (failInHandshake == null) {
throw e;
}
failInHandshake.setHostInUrl(host);
}
/// 2. VERIFY HOSTNAME
SSLSession newSession = null;
boolean verifiedHostname = true;
if (mHostnameVerifier != null) {
if (failInHandshake != null) {
/// 2.1 : a new SSLSession instance was NOT created in the handshake
X509Certificate serverCert = failInHandshake.getServerCertificate();
try {
mHostnameVerifier.verify(host, serverCert);
} catch (SSLException e) {
verifiedHostname = false;
}
} else {
/// 2.2 : a new SSLSession instance was created in the handshake
newSession = ((SSLSocket) socket).getSession();
if (!mTrustManager.isKnownServer((X509Certificate) (newSession.getPeerCertificates()[0]))) {
verifiedHostname = mHostnameVerifier.verify(host, newSession);
}
}
}
/// 3. Combine the exceptions to throw, if any
if (!verifiedHostname) {
SSLPeerUnverifiedException pue = new SSLPeerUnverifiedException(
"Names in the server certificate do not match to " + host + " in the URL"
);
if (failInHandshake == null) {
failInHandshake = new CertificateCombinedException(
(X509Certificate) newSession.getPeerCertificates()[0]
);
failInHandshake.setHostInUrl(host);
}
failInHandshake.setSslPeerUnverifiedException(pue);
pue.initCause(failInHandshake);
throw pue;
} else if (failInHandshake != null) {
SSLHandshakeException hse = new SSLHandshakeException("Server certificate could not be verified");
hse.initCause(failInHandshake);
throw hse;
}
} catch (IOException io) {
try {
socket.close();
} catch (Exception x) {
// NOTHING - irrelevant exception for the caller
}
throw io;
}
}
/**
* Grants that all protocols supported by the Security Provider in mSslContext are enabled in socket.
*
* Grants also that no unsupported protocol is tried to be enabled. That would trigger an exception, breaking
* the connection process although some protocols are supported.
*
* This is not cosmetic: not all the supported protocols are enabled by default. Too see an overview of
* supported and enabled protocols in the stock Security Provider in Android see the tables in
* http://developer.android.com/reference/javax/net/ssl/SSLSocket.html.
*
* @param socket
*/
private void enableSecureProtocols(Socket socket) {
SSLParameters params = mSslContext.getSupportedSSLParameters();
String[] supportedProtocols = params.getProtocols();
((SSLSocket) socket).setEnabledProtocols(supportedProtocols);
}
}

View File

@ -100,7 +100,7 @@ public class AdvancedX509TrustManager implements X509TrustManager {
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
* String authType)
*/
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
public void checkServerTrusted(X509Certificate[] certificates, String authType) {
if (!isKnownServer(certificates[0])) {
CertificateCombinedException result = new CertificateCombinedException(certificates[0]);
try {

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,64 +24,51 @@
package com.owncloud.android.lib.common.network;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.httpclient.methods.RequestEntity;
import android.util.Log;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import okhttp3.MediaType;
import okio.BufferedSink;
/**
* A RequestEntity that represents a PIECE of a file.
* A Request body that represents a file chunk and include information about the progress when uploading it
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
public class ChunkFromFileRequestBody extends FileRequestBody {
private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
private static final String TAG = ChunkFromFileRequestBody.class.getSimpleName();
//private final File mFile;
private final FileChannel mChannel;
private final String mContentType;
private final long mChunkSize;
private final File mFile;
private long mOffset;
private long mTransferred;
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
public ChunkFromFileChannelRequestEntity(
final FileChannel channel, final String contentType, long chunkSize, final File file
) {
super();
public ChunkFromFileRequestBody(File file, MediaType contentType, FileChannel channel, long chunkSize) {
super(file, contentType);
if (channel == null) {
throw new IllegalArgumentException("File may not be null");
}
if (chunkSize <= 0) {
throw new IllegalArgumentException("Chunk size must be greater than zero");
}
mChannel = channel;
mContentType = contentType;
mChunkSize = chunkSize;
mFile = file;
this.mChannel = channel;
this.mChunkSize = chunkSize;
mOffset = 0;
mTransferred = 0;
}
public void setOffset(long offset) {
mOffset = offset;
}
public long getContentLength() {
@Override
public long contentLength() {
try {
return Math.min(mChunkSize, mChannel.size() - mChannel.position());
} catch (IOException e) {
@ -89,39 +76,10 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
}
}
public String getContentType() {
return mContentType;
}
public boolean isRepeatable() {
return true;
}
@Override
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.add(listener);
}
}
@Override
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.addAll(listeners);
}
}
@Override
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.remove(listener);
}
}
public void writeRequest(final OutputStream out) throws IOException {
int readCount = 0;
Iterator<OnDatatransferProgressListener> it = null;
public void writeTo(BufferedSink sink) {
int readCount;
Iterator<OnDatatransferProgressListener> it;
try {
mChannel.position(mOffset);
@ -129,13 +87,20 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
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);
try {
out.write(mBuffer.array(), 0, readCount);
} catch (IOException io) {
// work-around try catch to filter exception in writing
throw new FileRequestEntity.WriteException(io);
}
Log_OC.d(TAG, "Read " + readCount + " bytes from file channel to " + mBuffer.toString());
sink.buffer().write(mBuffer.array(), 0 ,readCount);
sink.flush();
Log_OC.d(TAG, "Write " + readCount + " bytes to sink buffer with size " + sink.buffer().size());
mBuffer.clear();
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
mTransferred += readCount;
@ -148,20 +113,23 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
}
}
} catch (IOException io) {
// 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;
}
Log.d(TAG, "Chunk with size " + mChunkSize + " written in request body");
} catch (FileRequestEntity.WriteException we) {
throw we.getWrapped();
} 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;
// }
}
}
public void setOffset(long offset) {
this.mOffset = offset;
}
}

View File

@ -0,0 +1,120 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import android.util.Log;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.File;
import java.util.Collection;
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
*
* @author David González Verdugo
*/
public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer {
private static final String TAG = FileRequestBody.class.getSimpleName();
protected File mFile;
private MediaType mContentType;
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
public FileRequestBody(File file, MediaType contentType) {
mFile = file;
mContentType = contentType;
}
@Override
public MediaType contentType() {
return mContentType;
}
@Override
public long contentLength() {
return mFile.length();
}
@Override
public void writeTo(BufferedSink sink) {
Source source;
Iterator<OnDatatransferProgressListener> it;
try {
source = Okio.source(mFile);
long transferred = 0;
long read;
while ((read = source.read(sink.buffer(), 4096)) != -1) {
transferred += read;
sink.flush();
synchronized (mDataTransferListeners) {
it = mDataTransferListeners.iterator();
while (it.hasNext()) {
it.next().onTransferProgress(read, transferred, mFile.length(), mFile.getAbsolutePath());
}
}
}
Log.d(TAG, "File with name " + mFile.getName() + " and size " + mFile.length() +
" written in request body");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.add(listener);
}
}
@Override
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.addAll(listeners);
}
}
@Override
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.remove(listener);
}
}
}

View File

@ -1,166 +0,0 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.httpclient.methods.RequestEntity;
import com.owncloud.android.lib.common.utils.Log_OC;
/**
* A RequestEntity that represents a File.
*
*/
public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
final File mFile;
final String mContentType;
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
public FileRequestEntity(final File file, final String contentType) {
super();
this.mFile = file;
this.mContentType = contentType;
if (file == null) {
throw new IllegalArgumentException("File may not be null");
}
}
@Override
public long getContentLength() {
return mFile.length();
}
@Override
public String getContentType() {
return mContentType;
}
@Override
public boolean isRepeatable() {
return true;
}
@Override
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.add(listener);
}
}
@Override
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.addAll(listeners);
}
}
@Override
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.remove(listener);
}
}
@Override
public void writeRequest(final OutputStream out) throws IOException {
ByteBuffer tmp = ByteBuffer.allocate(4096);
int readResult = 0;
RandomAccessFile raf = new RandomAccessFile(mFile, "r");
FileChannel channel = raf.getChannel();
Iterator<OnDatatransferProgressListener> it = null;
long transferred = 0;
long size = mFile.length();
if (size == 0) size = -1;
try {
while ((readResult = channel.read(tmp)) >= 0) {
try {
out.write(tmp.array(), 0, readResult);
} catch (IOException io) {
// work-around try catch to filter exception in writing
throw new WriteException(io);
}
tmp.clear();
transferred += readResult;
synchronized (mDataTransferListeners) {
it = mDataTransferListeners.iterator();
while (it.hasNext()) {
it.next().onTransferProgress(readResult, transferred, size, mFile.getAbsolutePath());
}
}
}
} catch (IOException io) {
// 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;
}
} catch (WriteException we) {
throw we.getWrapped();
} finally {
try {
channel.close();
raf.close();
} catch (IOException io) {
// ignore failures closing source file
}
}
}
protected static class WriteException extends Exception {
IOException mWrapped;
WriteException(IOException wrapped) {
mWrapped = wrapped;
}
public IOException getWrapped() {
return mWrapped;
}
}
}

View File

@ -29,19 +29,13 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import android.content.Context;
@ -64,68 +58,8 @@ public class NetworkUtils {
/** Standard name for protocol TLS version 1.0 in JSSE API */
public static final String PROTOCOL_TLSv1_0 = "TLSv1";
/** Connection manager for all the OwnCloudClients */
private static MultiThreadedHttpConnectionManager mConnManager = null;
private static Protocol mDefaultHttpsProtocol = null;
private static AdvancedSslSocketFactory mAdvancedSslSocketFactory = null;
private static X509HostnameVerifier mHostnameVerifier = null;
/**
* Registers or unregisters the proper components for advanced SSL handling.
* @throws IOException
*/
@SuppressWarnings("deprecation")
public static void registerAdvancedSslContext(boolean register, Context context)
throws GeneralSecurityException, IOException {
Protocol pr = null;
try {
pr = Protocol.getProtocol("https");
if (pr != null && mDefaultHttpsProtocol == null) {
mDefaultHttpsProtocol = pr;
}
} catch (IllegalStateException e) {
// nothing to do here; really
}
boolean isRegistered = (pr != null && pr.getSocketFactory() instanceof AdvancedSslSocketFactory);
if (register && !isRegistered) {
Protocol.registerProtocol("https", new Protocol("https", getAdvancedSslSocketFactory(context), 443));
} else if (!register && isRegistered) {
if (mDefaultHttpsProtocol != null) {
Protocol.registerProtocol("https", mDefaultHttpsProtocol);
}
}
}
public static AdvancedSslSocketFactory getAdvancedSslSocketFactory(Context context)
throws GeneralSecurityException, IOException {
if (mAdvancedSslSocketFactory == null) {
KeyStore trustStore = getKnownServersStore(context);
AdvancedX509TrustManager trustMgr = new AdvancedX509TrustManager(trustStore);
TrustManager[] tms = new TrustManager[] { trustMgr };
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("TLSv1.2");
} catch (NoSuchAlgorithmException e) {
Log_OC.w(TAG, "TLSv1.2 is not supported in this device; falling through TLSv1.0");
sslContext = SSLContext.getInstance("TLSv1");
// should be available in any device; see reference of supported protocols in
// http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
}
sslContext.init(null, tms, null);
mHostnameVerifier = new BrowserCompatHostnameVerifier();
mAdvancedSslSocketFactory = new AdvancedSslSocketFactory(sslContext, trustMgr, mHostnameVerifier);
}
return mAdvancedSslSocketFactory;
}
private static String LOCAL_TRUSTSTORE_FILENAME = "knownServers.bks";
private static String LOCAL_TRUSTSTORE_PASSWORD = "password";
@ -147,7 +81,7 @@ public class NetworkUtils {
* @throws CertificateException When an exception occurred while loading the certificates from the local
* trust store.
*/
private static KeyStore getKnownServersStore(Context context)
public static KeyStore getKnownServersStore(Context context)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
if (mKnownServersStore == null) {
//mKnownServersStore = KeyStore.getInstance("BKS");
@ -184,16 +118,6 @@ public class NetworkUtils {
}
}
static public MultiThreadedHttpConnectionManager getMultiThreadedConnManager() {
if (mConnManager == null) {
mConnManager = new MultiThreadedHttpConnectionManager();
mConnManager.getParams().setDefaultMaxConnectionsPerHost(5);
mConnManager.getParams().setMaxTotalConnections(5);
}
return mConnManager;
}
public static boolean isCertInKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {

View File

@ -26,5 +26,5 @@
package com.owncloud.android.lib.common.network;
public interface OnDatatransferProgressListener {
public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileAbsoluteName);
void onTransferProgress(long read, long transferred, long percent, String absolutePath);
}

View File

@ -27,7 +27,6 @@ package com.owncloud.android.lib.common.network;
import java.util.Collection;
public interface ProgressiveDataTransferer {
public void addDatatransferProgressListener (OnDatatransferProgressListener listener);

View File

@ -27,14 +27,16 @@
package com.owncloud.android.lib.common.network;
import org.apache.commons.httpclient.HttpStatus;
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 com.owncloud.android.lib.common.operations.RemoteOperation}, and the status codes corresponding to all
* {@link RemoteOperation}, and the status codes corresponding to all
* of them.
*
* The last status code saved corresponds to the first response not being a redirection, unless the sequence exceeds
@ -108,7 +110,7 @@ public class RedirectionPath {
*/
public String getLastPermanentLocation() {
for (int i = mLastStatus; i >= 0; i--) {
if (mStatuses[i] == HttpStatus.SC_MOVED_PERMANENTLY && i <= mLastLocation) {
if (mStatuses[i] == HttpConstants.HTTP_MOVED_PERMANENTLY && i <= mLastLocation) {
return mLocations[i];
}
}

View File

@ -1,276 +0,0 @@
/** ownCloud Android Library is available under MIT license
*
* @author Christian Schabesberger
* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import java.math.BigDecimal;
import java.util.Date;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.property.DavProperty;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.apache.jackrabbit.webdav.xml.Namespace;
import android.net.Uri;
import com.owncloud.android.lib.common.utils.Log_OC;
public class WebdavEntry {
private static final String TAG = WebdavEntry.class.getSimpleName();
public static final String NAMESPACE_OC = "http://owncloud.org/ns";
public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
public static final String EXTENDED_PROPERTY_NAME_SIZE = "size";
public static final String EXTENDED_PROPERTY_NAME_PRIVATE_LINK = "privatelink";
public static final String PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes";
public static final String PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
private static final int CODE_PROP_NOT_FOUND = 404;
private String mName, mPath, mUri, mContentType, mEtag, mPermissions, mRemoteId, mPrivateLink;
private long mContentLength, mCreateTimestamp, mModifiedTimestamp, mSize;
private BigDecimal mQuotaUsedBytes, mQuotaAvailableBytes;
public WebdavEntry(MultiStatusResponse ms, String splitElement) {
resetData();
if (ms.getStatus().length != 0) {
mUri = ms.getHref();
mPath = mUri.split(splitElement, 2)[1];
int status = ms.getStatus()[0].getStatusCode();
if (status == CODE_PROP_NOT_FOUND) {
status = ms.getStatus()[1].getStatusCode();
}
DavPropertySet propSet = ms.getProperties(status);
@SuppressWarnings("rawtypes")
DavProperty prop = propSet.get(DavPropertyName.DISPLAYNAME);
if (prop != null) {
mName = (String) prop.getName().toString();
mName = mName.substring(1, mName.length() - 1);
} else {
String[] tmp = mPath.split("/");
if (tmp.length > 0)
mName = tmp[tmp.length - 1];
}
// use unknown mimetype as default behavior
// {DAV:}getcontenttype
mContentType = "application/octet-stream";
prop = propSet.get(DavPropertyName.GETCONTENTTYPE);
if (prop != null) {
mContentType = (String) prop.getValue();
// dvelasco: some builds of ownCloud server 4.0.x added a trailing ';'
// to the MIME type ; if looks fixed, but let's be cautious
if (mContentType.indexOf(";") >= 0) {
mContentType = mContentType.substring(0, mContentType.indexOf(";"));
}
}
// check if it's a folder in the standard way: see RFC2518 12.2 . RFC4918 14.3
// {DAV:}resourcetype
prop = propSet.get(DavPropertyName.RESOURCETYPE);
if (prop != null) {
Object value = prop.getValue();
if (value != null) {
mContentType = "DIR"; // a specific attribute would be better,
// but this is enough;
// unless while we have no reason to distinguish
// MIME types for folders
}
}
// {DAV:}getcontentlength
prop = propSet.get(DavPropertyName.GETCONTENTLENGTH);
if (prop != null)
mContentLength = Long.parseLong((String) prop.getValue());
// {DAV:}getlastmodified
prop = propSet.get(DavPropertyName.GETLASTMODIFIED);
if (prop != null) {
Date d = WebdavUtils
.parseResponseDate((String) prop.getValue());
mModifiedTimestamp = (d != null) ? d.getTime() : 0;
}
prop = propSet.get(DavPropertyName.CREATIONDATE);
if (prop != null) {
Date d = WebdavUtils
.parseResponseDate((String) prop.getValue());
mCreateTimestamp = (d != null) ? d.getTime() : 0;
}
// {DAV:}getetag
prop = propSet.get(DavPropertyName.GETETAG);
if (prop != null) {
mEtag = (String) prop.getValue();
mEtag = WebdavUtils.parseEtag(mEtag);
}
// {DAV:}quota-used-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_USED_BYTES));
if (prop != null) {
String quotaUsedBytesSt = (String) prop.getValue();
try {
mQuotaUsedBytes = new BigDecimal(quotaUsedBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaUsedBytes - NumberFormatException");
} catch (NullPointerException e) {
Log_OC.w(TAG, "No value for QuotaUsedBytes - NullPointerException");
}
Log_OC.d(TAG, "QUOTA_USED_BYTES " + quotaUsedBytesSt);
}
// {DAV:}quota-available-bytes
prop = propSet.get(DavPropertyName.create(PROPERTY_QUOTA_AVAILABLE_BYTES));
if (prop != null) {
String quotaAvailableBytesSt = (String) prop.getValue();
try {
mQuotaAvailableBytes = new BigDecimal(quotaAvailableBytesSt);
} catch (NumberFormatException e) {
Log_OC.w(TAG, "No value for QuotaAvailableBytes - NumberFormatException");
} catch (NullPointerException e) {
Log_OC.w(TAG, "No value for QuotaAvailableBytes");
}
Log_OC.d(TAG, "QUOTA_AVAILABLE_BYTES " + quotaAvailableBytesSt);
}
// OC permissions property <oc:permissions>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_PERMISSIONS, Namespace.getNamespace(NAMESPACE_OC)
);
if (prop != null && prop.getValue() != null) {
mPermissions = prop.getValue().toString();
}
// OC remote id property <oc:id>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_REMOTE_ID, Namespace.getNamespace(NAMESPACE_OC)
);
if (prop != null) {
mRemoteId = prop.getValue().toString();
}
// OC size property <oc:size>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_SIZE, Namespace.getNamespace(NAMESPACE_OC)
);
if (prop != null) {
mSize = Long.parseLong((String) prop.getValue());
}
// OC privatelink property <oc:privatelink>
prop = propSet.get(
EXTENDED_PROPERTY_NAME_PRIVATE_LINK, Namespace.getNamespace(NAMESPACE_OC)
);
if (prop != null) {
mPrivateLink = prop.getValue().toString();
}
} else {
Log_OC.e("WebdavEntry",
"General fuckup, no status for webdav response");
}
}
public String path() {
return mPath;
}
public String decodedPath() {
return Uri.decode(mPath);
}
public String name() {
return mName;
}
public boolean isDirectory() {
return mContentType.equals("DIR");
}
public String contentType() {
return mContentType;
}
public String uri() {
return mUri;
}
public long contentLength() {
return mContentLength;
}
public long createTimestamp() {
return mCreateTimestamp;
}
public long modifiedTimestamp() {
return mModifiedTimestamp;
}
public String etag() {
return mEtag;
}
public String permissions() {
return mPermissions;
}
public String remoteId() {
return mRemoteId;
}
public long size() {
return mSize;
}
public BigDecimal quotaUsedBytes() {
return mQuotaUsedBytes;
}
public BigDecimal quotaAvailableBytes() {
return mQuotaAvailableBytes;
}
public String privateLink() {
return mPrivateLink;
}
private void resetData() {
mName = mUri = mContentType = mPermissions = null;
mRemoteId = null;
mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
mSize = 0;
mQuotaUsedBytes = null;
mQuotaAvailableBytes = null;
mPrivateLink = null;
}
}

View File

@ -32,11 +32,7 @@ import java.util.Locale;
import android.net.Uri;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.xml.Namespace;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
public class WebdavUtils {
public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
@ -85,72 +81,6 @@ public class WebdavUtils {
return encodedPath;
}
/**
* Builds a DavPropertyNameSet with all prop
* For using instead of DavConstants.PROPFIND_ALL_PROP
* @return
*/
public static DavPropertyNameSet getAllPropSet(){
DavPropertyNameSet propSet = new DavPropertyNameSet();
propSet.add(DavPropertyName.DISPLAYNAME);
propSet.add(DavPropertyName.GETCONTENTTYPE);
propSet.add(DavPropertyName.RESOURCETYPE);
propSet.add(DavPropertyName.GETCONTENTLENGTH);
propSet.add(DavPropertyName.GETLASTMODIFIED);
propSet.add(DavPropertyName.CREATIONDATE);
propSet.add(DavPropertyName.GETETAG);
propSet.add(DavPropertyName.create(WebdavEntry.PROPERTY_QUOTA_USED_BYTES));
propSet.add(DavPropertyName.create(WebdavEntry.PROPERTY_QUOTA_AVAILABLE_BYTES));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_PERMISSIONS,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_REMOTE_ID,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_PRIVATE_LINK,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
return propSet;
}
/**
* Builds a DavPropertyNameSet with properties for files
* @return
*/
public static DavPropertyNameSet getFilePropSet(){
DavPropertyNameSet propSet = new DavPropertyNameSet();
propSet.add(DavPropertyName.DISPLAYNAME);
propSet.add(DavPropertyName.GETCONTENTTYPE);
propSet.add(DavPropertyName.RESOURCETYPE);
propSet.add(DavPropertyName.GETCONTENTLENGTH);
propSet.add(DavPropertyName.GETLASTMODIFIED);
propSet.add(DavPropertyName.CREATIONDATE);
propSet.add(DavPropertyName.GETETAG);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_PERMISSIONS,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_REMOTE_ID,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_SIZE,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
propSet.add(WebdavEntry.EXTENDED_PROPERTY_NAME_PRIVATE_LINK,
Namespace.getNamespace(WebdavEntry.NAMESPACE_OC));
return propSet;
}
/**
* Builds a DavPropertyNameSet with properties for user quotas
* @return set of quota properties
*/
public static DavPropertyNameSet getQuotaPropSet() {
DavPropertyNameSet propSet = new DavPropertyNameSet();
propSet.add(DavPropertyName.create(WebdavEntry.PROPERTY_QUOTA_AVAILABLE_BYTES));
propSet.add(DavPropertyName.create(WebdavEntry.PROPERTY_QUOTA_USED_BYTES));
return propSet;
}
/**
*
* @param rawEtag
@ -169,28 +99,26 @@ public class WebdavUtils {
return rawEtag;
}
/**
*
* @param method
* @return
* @param httpBaseMethod from which to get the etag
* @return etag from response
*/
public static String getEtagFromResponse(HttpMethod method) {
Header eTag = method.getResponseHeader("OC-ETag");
public static String getEtagFromResponse(HttpBaseMethod httpBaseMethod) {
String eTag = httpBaseMethod.getResponseHeader("OC-ETag");
if (eTag == null) {
eTag = method.getResponseHeader("oc-etag");
eTag = httpBaseMethod.getResponseHeader("oc-etag");
}
if (eTag == null) {
eTag = method.getResponseHeader("ETag");
eTag = httpBaseMethod.getResponseHeader("ETag");
}
if (eTag == null) {
eTag = method.getResponseHeader("etag");
eTag = httpBaseMethod.getResponseHeader("etag");
}
String result = "";
if (eTag != null) {
result = parseEtag(eTag.getValue());
result = eTag;
}
return result;
}
}

View File

@ -1,27 +1,3 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.operations;
import android.accounts.Account;
@ -39,16 +15,9 @@ import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
import okhttp3.OkHttpClient;
/**
* Operation which execution involves one or several interactions with an ownCloud server.
*
* Provides methods to execute the operation both synchronously or asynchronously.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public abstract class RemoteOperation implements Runnable {
public abstract class RemoteOperation<T extends Object> implements Runnable {
private static final String TAG = RemoteOperation.class.getSimpleName();
@ -65,82 +34,32 @@ public abstract class RemoteOperation implements Runnable {
/**
* ownCloud account in the remote ownCloud server to operate
*/
private Account mAccount = null;
protected Account mAccount = null;
/**
* Android Application context
*/
private Context mContext = null;
protected Context mContext = null;
/**
* Object to interact with the remote server
*/
private OwnCloudClient mClient = null;
protected OwnCloudClient mClient = null;
/**
* Object to interact with the remote server
*/
protected OkHttpClient mHttpClient = null;
/**
* Callback object to notify about the execution of the remote operation
*/
private OnRemoteOperationListener mListener = null;
protected OnRemoteOperationListener mListener = null;
/**
* Handler to the thread where mListener methods will be called
*/
private Handler mListenerHandler = null;
/**
* Abstract method to implement the operation in derived classes.
*/
protected abstract RemoteOperationResult run(OwnCloudClient client);
/**
* Synchronously executes the remote operation on the received ownCloud account.
*
* Do not call this method from the main thread.
*
* This method should be used whenever an ownCloud account is available, instead of
* {@link #execute(OwnCloudClient)}.
*
* @param account ownCloud account in remote ownCloud server to reach during the
* execution of the operation.
* @param context Android context for the component calling the method.
* @return Result of the operation.
*/
public RemoteOperationResult execute(Account account, Context context) {
if (account == null)
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Account");
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
*
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
* the operation.
* @return Result of the operation.
*/
public RemoteOperationResult execute(OwnCloudClient client) {
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();
}
mContext = client.getContext();
return runOperation();
}
protected Handler mListenerHandler = null;
/**
@ -219,6 +138,126 @@ public abstract class RemoteOperation implements Runnable {
return runnerThread;
}
protected void grantOwnCloudClient() throws
AccountUtils.AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException {
if (mClient == null) {
if (mAccount != null && mContext != null) {
OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, mContext);
} else {
throw new IllegalStateException("Trying to run a remote operation " +
"asynchronously with no client and no chance to create one (no account)");
}
}
}
/**
* Returns the current client instance to access the remote server.
*
* @return Current client instance to access the remote server.
*/
public final OwnCloudClient getClient() {
return mClient;
}
/**
* Abstract method to implement the operation in derived classes.
*/
protected abstract RemoteOperationResult<T> run(OwnCloudClient client);
/**
* Synchronously executes the remote operation on the received ownCloud account.
*
* Do not call this method from the main thread.
*
* This method should be used whenever an ownCloud account is available, instead of
* {@link #execute(OwnCloudClient)}.
*
* @param account ownCloud account in remote ownCloud server to reach during the
* execution of the operation.
* @param context Android context for the component calling the method.
* @return Result of the operation.
*/
public RemoteOperationResult<T> execute(Account account, Context context) {
if (account == null)
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Account");
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
*
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
* the operation.
* @return Result of the operation.
*/
public RemoteOperationResult<T> execute(OwnCloudClient client) {
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();
}
mContext = client.getContext();
return runOperation();
}
/**
* Synchronously executes the remote operation
*
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
* the operation.
* @return Result of the operation.
*/
public RemoteOperationResult<T> execute(OkHttpClient client, Context context) {
if (client == null)
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
mHttpClient = client;
mContext = context;
return runOperation();
}
/**
* Run operation for asynchronous or synchronous 'onExecute' method.
*
* 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
*/
private RemoteOperationResult<T> runOperation() {
RemoteOperationResult<T> result;
try {
grantOwnCloudClient();
result = run(mClient);
} catch (AccountsException | IOException e) {
Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
result = new RemoteOperationResult<>(e);
}
return result;
}
/**
* Asynchronous execution of the operation
@ -237,65 +276,10 @@ public abstract class RemoteOperation implements Runnable {
}
if (mListenerHandler != null && mListener != null) {
mListenerHandler.post(new Runnable() {
@Override
public void run() {
mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
}
});
mListenerHandler.post(() ->
mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend));
} else if (mListener != null) {
mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
}
}
/**
* Run operation for asynchronous or synchronous 'execute' method.
*
* 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
*/
private RemoteOperationResult runOperation() {
RemoteOperationResult result;
try {
grantOwnCloudClient();
result = run(mClient);
} catch (AccountsException | IOException e) {
Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
result = new RemoteOperationResult(e);
}
return result;
}
private void grantOwnCloudClient() throws
AccountUtils.AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException {
if (mClient == null) {
if (mAccount != null && mContext != null) {
OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, mContext);
} else {
throw new IllegalStateException("Trying to run a remote operation " +
"asynchronously with no client and no chance to create one (no account)");
}
}
}
/**
* Returns the current client instance to access the remote server.
*
* @return Current client instance to access the remote server.
*/
public final OwnCloudClient getClient() {
return mClient;
}
}

View File

@ -24,6 +24,17 @@
package com.owncloud.android.lib.common.operations;
import android.accounts.Account;
import android.accounts.AccountsException;
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 org.json.JSONException;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -34,35 +45,18 @@ import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import android.accounts.Account;
import android.accounts.AccountsException;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.json.JSONException;
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;
/**
* The result of a remote operation required to an ownCloud server.
*
* Provides a common classification of remote operation results for all the
* application.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class RemoteOperationResult implements Serializable {
public class RemoteOperationResult<T extends Object>
implements Serializable {
/**
* Generated - should be refreshed every time the class changes!!
@ -132,8 +126,7 @@ public class RemoteOperationResult implements Serializable {
private String mRedirectedLocation;
private ArrayList<String> mAuthenticate = new ArrayList<>();
private String mLastPermanentLocation = null;
private ArrayList<Object> mData;
private T mData = null;
/**
* Public constructor from result code.
@ -147,7 +140,22 @@ public class RemoteOperationResult implements Serializable {
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL ||
code == ResultCode.OK_NO_SSL ||
code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mData = null;
}
/**
* 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) {
mCode = prevRemoteOperation.mCode;
mHttpCode = prevRemoteOperation.mHttpCode;
mHttpPhrase = prevRemoteOperation.mHttpPhrase;
mAuthenticate = prevRemoteOperation.mAuthenticate;
mException = prevRemoteOperation.mException;
mLastPermanentLocation = prevRemoteOperation.mLastPermanentLocation;
mSuccess = prevRemoteOperation.mSuccess;
mRedirectedLocation = prevRemoteOperation.mRedirectedLocation;
}
/**
@ -171,33 +179,34 @@ public class RemoteOperationResult implements Serializable {
} else if (e instanceof SocketTimeoutException) {
mCode = ResultCode.TIMEOUT;
} else if (e instanceof ConnectTimeoutException) {
mCode = ResultCode.TIMEOUT;
} else if (e instanceof MalformedURLException) {
mCode = ResultCode.INCORRECT_ADDRESS;
} else if (e instanceof UnknownHostException) {
mCode = ResultCode.HOST_NOT_AVAILABLE;
} else if (e instanceof AccountNotFoundException) {
} else if (e instanceof AccountUtils.AccountNotFoundException) {
mCode = ResultCode.ACCOUNT_NOT_FOUND;
} else if (e instanceof AccountsException) {
mCode = ResultCode.ACCOUNT_EXCEPTION;
} else if (e instanceof SSLException || e instanceof RuntimeException) {
CertificateCombinedException se = getCertificateCombinedException(e);
if (se != null) {
mException = se;
if (se.isRecoverable()) {
mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
}
} else if (e instanceof RuntimeException) {
mCode = ResultCode.HOST_NOT_AVAILABLE;
if(e instanceof SSLPeerUnverifiedException) {
mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
} else {
mCode = ResultCode.SSL_ERROR;
CertificateCombinedException se = getCertificateCombinedException(e);
if (se != null) {
mException = se;
if (se.isRecoverable()) {
mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
}
} else if (e instanceof RuntimeException) {
mCode = ResultCode.HOST_NOT_AVAILABLE;
} else {
mCode = ResultCode.SSL_ERROR;
}
}
} else if (e instanceof FileNotFoundException) {
@ -206,7 +215,6 @@ public class RemoteOperationResult implements Serializable {
} else {
mCode = ResultCode.UNKNOWN_ERROR;
}
}
/**
@ -216,25 +224,21 @@ public class RemoteOperationResult implements Serializable {
*
* 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.
* response body
*
* @param success The operation was considered successful or not.
* @param httpMethod HTTP/DAV method already executed which response will be examined to interpret the
* result.
* @param httpMethod
* @throws IOException
*/
public RemoteOperationResult(boolean success, HttpMethod httpMethod) throws IOException {
this(
success,
httpMethod.getStatusCode(),
httpMethod.getStatusText(),
public RemoteOperationResult(HttpBaseMethod httpMethod) throws IOException {
this(httpMethod.getStatusCode(),
httpMethod.getStatusMessage(),
httpMethod.getResponseHeaders()
);
if (mHttpCode == HttpStatus.SC_BAD_REQUEST) { // 400
if (mHttpCode == HttpConstants.HTTP_BAD_REQUEST) { // 400
String bodyResponse = httpMethod.getResponseBodyAsString();
// do not get for other HTTP codes!; could not be available
// do not get for other HTTP codes!; could not be available
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
@ -250,34 +254,40 @@ public class RemoteOperationResult implements Serializable {
}
}
if (mHttpCode == HttpStatus.SC_FORBIDDEN) { // 403
parseErrorMessageAndSetCode(httpMethod, ResultCode.SPECIFIC_FORBIDDEN);
}
if (mHttpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE) { // 415
parseErrorMessageAndSetCode(httpMethod, ResultCode.SPECIFIC_UNSUPPORTED_MEDIA_TYPE);
}
if (mHttpCode == HttpStatus.SC_SERVICE_UNAVAILABLE) { // 503
parseErrorMessageAndSetCode(httpMethod, ResultCode.SPECIFIC_SERVICE_UNAVAILABLE);
// before
switch (mHttpCode) {
case HttpConstants.HTTP_FORBIDDEN:
parseErrorMessageAndSetCode(
httpMethod.getResponseBodyAsString(),
ResultCode.SPECIFIC_FORBIDDEN
);
break;
case HttpConstants.HTTP_UNSUPPORTED_MEDIA_TYPE:
parseErrorMessageAndSetCode(
httpMethod.getResponseBodyAsString(),
ResultCode.SPECIFIC_UNSUPPORTED_MEDIA_TYPE
);
break;
case HttpConstants.HTTP_SERVICE_UNAVAILABLE:
parseErrorMessageAndSetCode(
httpMethod.getResponseBodyAsString(),
ResultCode.SPECIFIC_SERVICE_UNAVAILABLE
);
break;
default:
break;
}
}
/**
* Parse the error message included in the body response, if any, and set the specific result
* code
* @param httpMethod HTTP/DAV method already executed which response body will be parsed to get
* the specific error message
* @param resultCode specific result code
*
* @param bodyResponse okHttp response body
* @param resultCode our own custom result code
* @throws IOException
*/
private void parseErrorMessageAndSetCode(HttpMethod httpMethod, ResultCode resultCode)
throws IOException {
String bodyResponse = httpMethod.getResponseBodyAsString();
private void parseErrorMessageAndSetCode(String bodyResponse, ResultCode resultCode) {
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
@ -301,31 +311,29 @@ public class RemoteOperationResult implements Serializable {
* 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).
*
* If all the fields come from the same HTTP/DAV response, {@link #RemoteOperationResult(boolean, HttpMethod)}
* should be used instead.
*
* Determines a {@link ResultCode} depending on the HTTP code and HTTP response headers received.
*
* @param success The operation was considered successful or not.
* @param httpCode HTTP status code returned by an HTTP/DAV method.
* @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method
* @param httpHeaders HTTP response header returned by an HTTP/DAV method
* @param headers HTTP response header returned by an HTTP/DAV method
*/
public RemoteOperationResult(boolean success, int httpCode, String httpPhrase, Header[] httpHeaders) {
this(success, httpCode, httpPhrase);
if (httpHeaders != null) {
for (Header httpHeader : httpHeaders) {
if ("location".equals(httpHeader.getName().toLowerCase())) {
mRedirectedLocation = httpHeader.getValue();
public RemoteOperationResult(int httpCode, String httpPhrase, Headers headers) {
this(httpCode, httpPhrase);
if (headers != null) {
for (Map.Entry<String, List<String>> header : headers.toMultimap().entrySet()) {
if ("location".equals(header.getKey().toLowerCase())) {
mRedirectedLocation = header.getValue().get(0);
continue;
}
if ("www-authenticate".equals(httpHeader.getName().toLowerCase())) {
mAuthenticate.add(httpHeader.getValue().toLowerCase());
if ("www-authenticate".equals(header.getKey().toLowerCase())) {
mAuthenticate.add(header.getValue().get(0).toLowerCase());
}
}
}
if (isIdPRedirection()) {
mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN
// overrides default ResultCode.UNKNOWN
mCode = ResultCode.UNAUTHORIZED;
}
}
@ -334,58 +342,47 @@ public class RemoteOperationResult implements Serializable {
*
* Determines a {@link ResultCode} depending of the type of the exception.
*
* @param success Operation was successful or not.
* @param httpCode HTTP status code returned by the HTTP/DAV method.
* @param httpPhrase HTTP status line phrase returned by the HTTP/DAV method
*/
private RemoteOperationResult(boolean success, int httpCode, String httpPhrase) {
mSuccess = success;
private RemoteOperationResult(int httpCode, String httpPhrase) {
mHttpCode = httpCode;
mHttpPhrase = httpPhrase;
if (success) {
mCode = ResultCode.OK;
} else if (httpCode > 0) {
if (httpCode > 0) {
switch (httpCode) {
case HttpStatus.SC_UNAUTHORIZED: // 401
case HttpConstants.HTTP_UNAUTHORIZED: // 401
mCode = ResultCode.UNAUTHORIZED;
break;
case HttpStatus.SC_FORBIDDEN: // 403
case HttpConstants.HTTP_FORBIDDEN: // 403
mCode = ResultCode.FORBIDDEN;
break;
case HttpStatus.SC_NOT_FOUND: // 404
case HttpConstants.HTTP_NOT_FOUND: // 404
mCode = ResultCode.FILE_NOT_FOUND;
break;
case HttpStatus.SC_CONFLICT: // 409
case HttpConstants.HTTP_CONFLICT: // 409
mCode = ResultCode.CONFLICT;
break;
case HttpStatus.SC_INTERNAL_SERVER_ERROR: // 500
case HttpConstants.HTTP_INTERNAL_SERVER_ERROR: // 500
mCode = ResultCode.INSTANCE_NOT_CONFIGURED; // assuming too much...
break;
case HttpStatus.SC_SERVICE_UNAVAILABLE: // 503
case HttpConstants.HTTP_SERVICE_UNAVAILABLE: // 503
mCode = ResultCode.SERVICE_UNAVAILABLE;
break;
case HttpStatus.SC_INSUFFICIENT_STORAGE: // 507
case HttpConstants.HTTP_INSUFFICIENT_STORAGE: // 507
mCode = ResultCode.QUOTA_EXCEEDED; // surprise!
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE; // UNKNOWN ERROR
Log_OC.d(TAG,
"RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
mHttpCode + " " + mHttpPhrase
);
}
}
}
public void setData(ArrayList<Object> items) {
mData = items;
}
public ArrayList<Object> getData() {
return mData;
}
public boolean isSuccess() {
return mSuccess;
@ -449,9 +446,6 @@ public class RemoteOperationResult implements Serializable {
} else if (mException instanceof SocketTimeoutException) {
return "Socket timeout exception";
} else if (mException instanceof ConnectTimeoutException) {
return "Connect timeout exception";
} else if (mException instanceof MalformedURLException) {
return "Malformed URL exception";
@ -476,9 +470,9 @@ public class RemoteOperationResult implements Serializable {
} else if (mException instanceof IOException) {
return "Unrecovered transport exception";
} else if (mException instanceof AccountNotFoundException) {
} else if (mException instanceof AccountUtils.AccountNotFoundException) {
Account failedAccount =
((AccountNotFoundException) mException).getFailedAccount();
((AccountUtils.AccountNotFoundException) mException).getFailedAccount();
return mException.getMessage() + " (" +
(failedAccount != null ? failedAccount.name : "NULL") + ")";
@ -530,7 +524,7 @@ public class RemoteOperationResult implements Serializable {
}
public boolean isServerFail() {
return (mHttpCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR);
return (mHttpCode >= HttpConstants.HTTP_INTERNAL_SERVER_ERROR);
}
public boolean isException() {
@ -572,4 +566,15 @@ public class RemoteOperationResult implements Serializable {
mLastPermanentLocation = lastPermanentLocation;
}
public void setSuccess(boolean success) {
this.mSuccess = success;
}
public void setData(T data) {
mData = data;
}
public T getData() {
return mData;
}
}

View File

@ -1,5 +1,7 @@
package com.owncloud.android.lib.common.utils;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
@ -7,10 +9,6 @@ import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.os.Environment;
import android.util.Log;
public class Log_OC {
private static final String SIMPLE_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss";
private static final String LOG_FOLDER_NAME = "log";
@ -64,11 +62,6 @@ public class Log_OC {
appendLog(TAG+" : "+ message);
}
public static void wtf(String TAG, String message) {
Log.wtf(TAG, message);
appendLog(TAG+" : "+ message);
}
/**
* Start doing logging
* @param storagePath : directory for keeping logs

View File

@ -0,0 +1,63 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.utils;
import java.util.Random;
/**
* Class with methods to generate random values
*
* @author David González Verdugo
*/
public class RandomUtils {
private static final String CANDIDATECHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"1234567890-+/_=.:";
/**
* @param length the number of random chars to be generated
*
* @return String containing random chars
*/
public static String generateRandomString(int length) {
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(CANDIDATECHARS.charAt(random.nextInt(CANDIDATECHARS.length())));
}
return sb.toString();
}
/**
* @param min minimum integer to obtain randomly
* @param max maximum integer to obtain randomly
* @return random integer between min and max
*/
public static int generateRandomInteger(int min, int max) {
Random r = new Random();
return r.nextInt(max-min) + min;
}
}

View File

@ -1,151 +0,0 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Random;
import org.apache.commons.httpclient.methods.PutMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation {
private static final int LAST_CHUNK_TIMEOUT = 900000; //15 mins.
public static final long CHUNK_SIZE = 1024000;
private static final String OC_CHUNKED_HEADER = "OC-Chunked";
private static final String OC_CHUNK_SIZE_HEADER = "OC-Chunk-Size";
private static final String OC_CHUNK_X_OC_MTIME_HEADER = "X-OC-Mtime";
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType,
String fileLastModifTimestamp) {
super(storagePath, remotePath, mimeType, fileLastModifTimestamp);
}
public ChunkedUploadRemoteFileOperation(
String storagePath, String remotePath, String mimeType, String requiredEtag,
String fileLastModifTimestamp
) {
super(storagePath, remotePath, mimeType, requiredEtag, fileLastModifTimestamp);
}
@Override
protected RemoteOperationResult uploadFile(OwnCloudClient client) throws IOException {
int status = -1;
RemoteOperationResult result = null;
FileChannel channel = null;
RandomAccessFile raf = null;
try {
File file = new File(mLocalPath);
raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file);
synchronized (mDataTransferListeners) {
((ProgressiveDataTransferer) mEntity)
.addDatatransferProgressListeners(mDataTransferListeners);
}
long offset = 0;
String uriPrefix = client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath) +
"-chunking-" + Math.abs((new Random()).nextInt(9000) + 1000) + "-";
long totalLength = file.length();
long chunkCount = (long) Math.ceil((double) totalLength / CHUNK_SIZE);
String chunkSizeStr = String.valueOf(CHUNK_SIZE);
String totalLengthStr = String.valueOf(file.length());
for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++, offset += CHUNK_SIZE) {
if (chunkIndex == chunkCount - 1) {
chunkSizeStr = String.valueOf(CHUNK_SIZE * chunkCount - totalLength);
}
if (mPutMethod != null) {
mPutMethod.releaseConnection(); // let the connection available
// for other methods
}
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
mPutMethod.addRequestHeader(OC_CHUNK_SIZE_HEADER, chunkSizeStr);
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, totalLengthStr);
mPutMethod.addRequestHeader(OC_CHUNK_X_OC_MTIME_HEADER, mFileLastModifTimestamp);
((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset);
mPutMethod.setRequestEntity(mEntity);
if (mCancellationRequested.get()) {
mPutMethod.abort();
// next method will throw an exception
}
if (chunkIndex == chunkCount - 1) {
// Added a high timeout to the last chunk due to when the last chunk
// arrives to the server with the last PUT, all chunks get assembled
// within that PHP request, so last one takes longer.
mPutMethod.getParams().setSoTimeout(LAST_CHUNK_TIMEOUT);
}
status = client.executeMethod(mPutMethod);
result = new RemoteOperationResult(
isSuccess(status),
mPutMethod
);
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath +
", chunk index " + chunkIndex + ", count " + chunkCount +
", HTTP result status " + status);
if (!isSuccess(status))
break;
}
} finally {
if (channel != null)
channel.close();
if (raf != null)
raf.close();
if (mPutMethod != null)
mPutMethod.releaseConnection(); // let the connection available for other methods
}
return result;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -27,28 +27,25 @@ package com.owncloud.android.lib.resources.files;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.CopyMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
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 com.owncloud.android.lib.resources.status.OwnCloudVersion;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.Status;
import org.apache.jackrabbit.webdav.client.methods.CopyMethod;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
* in the same account.
* <p/>
*
* Allows renaming the moving file/folder at the same time.
*
* @author David A. Velasco
* @author Christian Schabesberger
*/
public class CopyRemoteFileOperation extends RemoteOperation {
@ -62,7 +59,6 @@ public class CopyRemoteFileOperation extends RemoteOperation {
private boolean mOverwrite;
/**
* Constructor.
* <p/>
@ -78,7 +74,6 @@ public class CopyRemoteFileOperation extends RemoteOperation {
mOverwrite = overwrite;
}
/**
* Performs the rename operation.
*
@ -93,36 +88,35 @@ public class CopyRemoteFileOperation extends RemoteOperation {
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
return new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (mTargetRemotePath.equals(mSrcRemotePath)) {
// nothing to do!
return new RemoteOperationResult(ResultCode.OK);
return new RemoteOperationResult<>(ResultCode.OK);
}
if (mTargetRemotePath.startsWith(mSrcRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT);
return new RemoteOperationResult<>(ResultCode.INVALID_COPY_INTO_DESCENDANT);
}
/// perform remote operation
CopyMethod copyMethod = null;
RemoteOperationResult result = null;
try {
copyMethod = new CopyMethod(
client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath),
mOverwrite
);
int status = client.executeMethod(copyMethod, COPY_READ_TIMEOUT, COPY_CONNECTION_TIMEOUT);
CopyMethod copyMethod = new CopyMethod(new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mSrcRemotePath)),
client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mTargetRemotePath),
mOverwrite);
/// process response
if (status == HttpStatus.SC_MULTI_STATUS) {
result = processPartialError(copyMethod);
copyMethod.setReadTimeout(COPY_READ_TIMEOUT, TimeUnit.SECONDS);
copyMethod.setConnectionTimeout(COPY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
} else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) {
final int status = client.executeHttpMethod(copyMethod);
result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
if(status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT) {
result = new RemoteOperationResult<>(ResultCode.OK);
} else if (status == HttpConstants.HTTP_PRECONDITION_FAILED && !mOverwrite) {
result = new RemoteOperationResult<>(ResultCode.INVALID_OVERWRITE);
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
@ -130,7 +124,7 @@ public class CopyRemoteFileOperation extends RemoteOperation {
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
} else {
result = new RemoteOperationResult(isSuccess(status), copyMethod);
result = new RemoteOperationResult<>(copyMethod);
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
}
@ -138,67 +132,11 @@ public class CopyRemoteFileOperation extends RemoteOperation {
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage(), e);
} finally {
if (copyMethod != null)
copyMethod.releaseConnection();
}
return result;
}
/**
* Analyzes a multistatus response from the OC server to generate an appropriate result.
* <p/>
* In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some
* children are copied, some other aren't.
* <p/>
* According to the WebDAV specification, a multistatus response SHOULD NOT include partial
* successes (201, 204) nor for descendants of already failed children (424) in the response
* entity. But SHOULD NOT != MUST NOT, so take carefully.
*
* @param copyMethod Copy operation just finished with a multistatus response
* @return A result for the {@link com.owncloud.android.lib.resources.files.CopyRemoteFileOperation} caller
* @throws java.io.IOException If the response body could not be parsed
* @throws org.apache.jackrabbit.webdav.DavException If the status code is other than MultiStatus or if obtaining
* the response XML document fails
*/
private RemoteOperationResult processPartialError(CopyMethod copyMethod)
throws IOException, DavException {
// Adding a list of failed descendants to the result could be interesting; or maybe not.
// For the moment, let's take the easy way.
/// check that some error really occurred
MultiStatusResponse[] responses = copyMethod.getResponseBodyAsMultiStatus().getResponses();
Status[] status;
boolean failFound = false;
for (int i = 0; i < responses.length && !failFound; i++) {
status = responses[i].getStatus();
failFound = (
status != null &&
status.length > 0 &&
status[0].getStatusCode() > 299
);
}
RemoteOperationResult result;
if (failFound) {
result = new RemoteOperationResult(ResultCode.PARTIAL_COPY_DONE);
} else {
result = new RemoteOperationResult(true, copyMethod);
}
return result;
}
protected boolean isSuccess(int status) {
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
}
}

View File

@ -24,16 +24,22 @@
package com.owncloud.android.lib.resources.files;
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.MkColMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
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 com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Remote operation performing the creation of a new folder in the ownCloud server.
@ -48,20 +54,19 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
private static final int READ_TIMEOUT = 30000;
private static final int CONNECTION_TIMEOUT = 5000;
protected String mRemotePath;
protected boolean mCreateFullPath;
private String mRemotePath;
private boolean mCreateFullPath;
protected boolean createChunksFolder;
/**
* Constructor
*
* @param remotePath Full path to the new directory to create in the remote server.
* @param createFullPath 'True' means that all the ancestor folders should be created
* if don't exist yet.
* @param createFullPath 'True' means that all the ancestor folders should be created.
*/
public CreateRemoteFolderOperation(String remotePath, boolean createFullPath) {
mRemotePath = remotePath;
mCreateFullPath = createFullPath;
createChunksFolder = false;
}
/**
@ -71,7 +76,7 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
RemoteOperationResult result;
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
@ -85,41 +90,38 @@ public class CreateRemoteFolderOperation extends RemoteOperation {
result = createFolder(client); // second (and last) try
}
}
} else {
result = new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
result = new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
return result;
}
private RemoteOperationResult createFolder(OwnCloudClient client) {
RemoteOperationResult result = null;
MkColMethod mkcol = null;
RemoteOperationResult result;
try {
mkcol = new MkColMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
result = new RemoteOperationResult(mkcol.succeeded(), mkcol);
Uri webDavUri = createChunksFolder ? client.getNewUploadsWebDavUri() : client.getNewFilesWebDavUri();
final MkColMethod mkcol = new MkColMethod(new URL(webDavUri + WebdavUtils.encodePath(mRemotePath)));
mkcol.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
mkcol.setConnectionTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
final int status = client.executeHttpMethod(mkcol);
result = (status == HttpConstants.HTTP_CREATED)
? new RemoteOperationResult<>(ResultCode.OK)
: new RemoteOperationResult<>(mkcol);
Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
client.exhaustResponse(mkcol.getResponseBodyAsStream());
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
} finally {
if (mkcol != null)
mkcol.releaseConnection();
}
return result;
}
private RemoteOperationResult createParentFolder(String parentPath, OwnCloudClient client) {
RemoteOperation operation = new CreateRemoteFolderOperation(parentPath,
mCreateFullPath);
RemoteOperation operation = new CreateRemoteFolderOperation(parentPath, mCreateFullPath);
return operation.execute(client);
}
}

View File

@ -24,21 +24,9 @@
package com.owncloud.android.lib.resources.files;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
@ -46,6 +34,16 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Remote operation performing the download of a remote file in the ownCloud server.
*
@ -88,7 +86,7 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage(), e);
}
@ -98,28 +96,30 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
private RemoteOperationResult downloadFile(OwnCloudClient client, File targetFile) throws
IOException, OperationCancelledException {
Exception {
RemoteOperationResult result;
int status;
boolean savedFile = false;
mGet = new GetMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
mGet = new GetMethod(new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)));
Iterator<OnDatatransferProgressListener> it;
FileOutputStream fos = null;
BufferedInputStream bis = null;
try {
status = client.executeMethod(mGet);
status = client.executeHttpMethod(mGet);
if (isSuccess(status)) {
targetFile.createNewFile();
bis = new BufferedInputStream(mGet.getResponseBodyAsStream());
fos = new FileOutputStream(targetFile);
long transferred = 0;
Header contentLength = mGet.getResponseHeader("Content-Length");
long totalToTransfer = (contentLength != null &&
contentLength.getValue().length() > 0) ?
Long.parseLong(contentLength.getValue()) : 0;
String contentLength = mGet.getResponseHeader(HttpConstants.CONTENT_LENGTH_HEADER);
long totalToTransfer =
(contentLength != null
&& contentLength.length() > 0)
? Long.parseLong(contentLength)
: 0;
byte[] bytes = new byte[4096];
int readResult;
@ -142,18 +142,23 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
}
if (transferred == totalToTransfer) { // Check if the file is completed
savedFile = true;
Header modificationTime = mGet.getResponseHeader("Last-Modified");
if (modificationTime == null) {
modificationTime = mGet.getResponseHeader("last-modified");
}
final String modificationTime =
mGet.getResponseHeaders().get("Last-Modified") != null
? mGet.getResponseHeaders().get("Last-Modified")
: mGet.getResponseHeader("last-modified");
if (modificationTime != null) {
Date d = WebdavUtils.parseResponseDate(modificationTime.getValue());
final Date d = WebdavUtils.parseResponseDate(modificationTime);
mModificationTimestamp = (d != null) ? d.getTime() : 0;
} else {
Log_OC.e(TAG, "Could not read modification time from response downloading " + mRemotePath);
}
mEtag = WebdavUtils.getEtagFromResponse(mGet);
// Get rid of extra quotas
mEtag = mEtag.replace("\"", "");
if (mEtag.length() == 0) {
Log_OC.e(TAG, "Could not read eTag from response downloading " + mRemotePath);
}
@ -168,21 +173,21 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
} // else, body read by RemoteOperationResult constructor
result = new RemoteOperationResult(isSuccess(status), mGet);
result = isSuccess(status)
? new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK)
: new RemoteOperationResult<>(mGet);
} finally {
if (fos != null) fos.close();
if (bis != null) bis.close();
if (!savedFile && targetFile.exists()) {
targetFile.delete();
}
mGet.releaseConnection(); // let the connection available for other methods
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
private String getTmpPath() {

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,47 +24,50 @@
package com.owncloud.android.lib.resources.files;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import android.content.Context;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Operation to check the existence or absence of a path in a remote server.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class ExistenceCheckRemoteOperation extends RemoteOperation {
/** Maximum time to wait for a response from the server in MILLISECONDs. */
/**
* Maximum time to wait for a response from the server in MILLISECONDs.
*/
public static final int TIMEOUT = 10000;
private static final String TAG = ExistenceCheckRemoteOperation.class.getSimpleName();
private static final int FORBIDDEN_ERROR = 403;
private static final int SERVICE_UNAVAILABLE_ERROR = 503;
private String mPath;
private boolean mSuccessIfAbsent;
/** Sequence of redirections followed. Available only after executing the operation */
/**
* Sequence of redirections followed. Available only after executing the operation
*/
private RedirectionPath mRedirectionPath = null;
// TODO move to {@link RemoteOperation}, that needs a nice refactoring
/**
* Full constructor. Success of the operation will depend upon the value of successIfAbsent.
*
* @param remotePath Path to append to the URL owned by the client instance.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
* @param remotePath Path to append to the URL owned by the client instance.
* @param successIfAbsent When 'true', the operation finishes in success if the path does
* NOT exist in the remote server (HTTP 404).
*/
public ExistenceCheckRemoteOperation(String remotePath, boolean successIfAbsent) {
mPath = (remotePath != null) ? remotePath : "";
@ -72,69 +75,73 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
PropFindMethod propfind = null;
boolean previousFollowRedirects = client.getFollowRedirects();
protected RemoteOperationResult run(OwnCloudClient client) {
boolean previousFollowRedirects = client.followRedirects();
try {
propfind = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mPath),
WebdavUtils.getAllPropSet(), DavConstants.DEPTH_0);
PropfindMethod propfindMethod = new PropfindMethod(
new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mPath)),
0,
DavUtils.getAllPropset()
);
propfindMethod.setReadTimeout(TIMEOUT, TimeUnit.SECONDS);
propfindMethod.setConnectionTimeout(TIMEOUT, TimeUnit.SECONDS);
client.setFollowRedirects(false);
int status = client.executeMethod(propfind, TIMEOUT, TIMEOUT);
int status = client.executeHttpMethod(propfindMethod);
if (previousFollowRedirects) {
mRedirectionPath = client.followRedirection(propfind);
mRedirectionPath = client.followRedirection(propfindMethod);
status = mRedirectionPath.getLastStatus();
}
if (status != FORBIDDEN_ERROR && status != SERVICE_UNAVAILABLE_ERROR) {
client.exhaustResponse(propfind.getResponseBodyAsStream());
}
/**
* PROPFIND method
* 404 NOT FOUND: path doesn't exist,
* 207 MULTI_STATUS: path exists.
*/
boolean success = ((status == HttpStatus.SC_OK || status == HttpStatus.SC_MULTI_STATUS) &&
!mSuccessIfAbsent) ||
(status == HttpStatus.SC_MULTI_STATUS && !mSuccessIfAbsent) ||
(status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
result = new RemoteOperationResult(
success,
propfind
);
Log_OC.d(TAG, "Existence check for " + client.getWebdavUri() +
Log_OC.d(TAG, "Existence check for " + client.getNewFilesWebDavUri() +
WebdavUtils.encodePath(mPath) + " targeting for " +
(mSuccessIfAbsent ? " absence " : " existence ") +
"finished with HTTP status " + status + (!success?"(FAIL)":""));
"finished with HTTP status " + status + (!isSuccess(status) ? "(FAIL)" : ""));
return isSuccess(status)
? new RemoteOperationResult<>(OK)
: new RemoteOperationResult<>(propfindMethod);
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Existence check for " + client.getWebdavUri() +
final RemoteOperationResult result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Existence check for " + client.getNewFilesWebDavUri() +
WebdavUtils.encodePath(mPath) + " targeting for " +
(mSuccessIfAbsent ? " absence " : " existence ") + ": " +
result.getLogMessage(), result.getException());
return result;
} finally {
if (propfind != null)
propfind.releaseConnection();
client.setFollowRedirects(previousFollowRedirects);
}
return result;
}
}
/**
* Gets the sequence of redirections followed during the execution of the operation.
*
* @return Sequence of redirections followed, if any, or NULL if the operation was not executed.
* @return Sequence of redirections followed, if any, or NULL if the operation was not executed.
*/
public RedirectionPath getRedirectionPath() {
return mRedirectionPath;
}
/**
* @return 'True' if the operation was executed and at least one redirection was followed.
* @return 'True' if the operation was executed and at least one redirection was followed.
*/
public boolean wasRedirected() {
return (mRedirectionPath != null && mRedirectionPath.getRedirectionsCount() > 0);
}
private boolean isSuccess(int status) {
return ((status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_MULTI_STATUS) && !mSuccessIfAbsent)
|| (status == HttpConstants.HTTP_MULTI_STATUS && !mSuccessIfAbsent)
|| (status == HttpConstants.HTTP_NOT_FOUND && mSuccessIfAbsent);
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,17 +24,16 @@
package com.owncloud.android.lib.resources.files;
import java.io.File;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.io.File;
public class FileUtils {
private static final String TAG = FileUtils.class.getSimpleName();
public static final String PATH_SEPARATOR = "/";
public static final String FINAL_CHUNKS_FILE = ".file";
public static String getParentPath(String remotePath) {
String parentPath = new File(remotePath).getParent();
@ -82,5 +81,4 @@ public class FileUtils {
}
return result;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,31 +24,29 @@
package com.owncloud.android.lib.resources.files;
import java.io.IOException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.Status;
import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
import android.net.Uri;
import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
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 com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
* in the same account.
* <p>
*
* Allows renaming the moving file/folder at the same time.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class MoveRemoteFileOperation extends RemoteOperation {
@ -59,28 +57,29 @@ public class MoveRemoteFileOperation extends RemoteOperation {
private String mSrcRemotePath;
private String mTargetRemotePath;
private boolean mOverwrite;
protected boolean moveChunkedFile = false;
protected String mFileLastModifTimestamp;
protected long mFileLength;
/**
* Constructor.
* <p>
*
* TODO Paths should finish in "/" in the case of folders. ?
*
* @param srcRemotePath Remote path of the file/folder to move.
* @param targetRemotePath Remove path desired for the file/folder after moving it.
* @param targetRemotePath Remote path desired for the file/folder after moving it.
*/
public MoveRemoteFileOperation(
String srcRemotePath, String targetRemotePath, boolean overwrite
) {
public MoveRemoteFileOperation(String srcRemotePath,
String targetRemotePath,
boolean overwrite) {
mSrcRemotePath = srcRemotePath;
mTargetRemotePath = targetRemotePath;
mOverwrite = overwrite;
}
/**
* Performs the rename operation.
*
@ -95,45 +94,52 @@ public class MoveRemoteFileOperation extends RemoteOperation {
/// check parameters
if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) {
return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
return new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (mTargetRemotePath.equals(mSrcRemotePath)) {
// nothing to do!
return new RemoteOperationResult(ResultCode.OK);
return new RemoteOperationResult<>(ResultCode.OK);
}
if (mTargetRemotePath.startsWith(mSrcRemotePath)) {
return new RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT);
return new RemoteOperationResult<>(ResultCode.INVALID_MOVE_INTO_DESCENDANT);
}
/// perform remote operation
MoveMethod move = null;
RemoteOperationResult result = null;
RemoteOperationResult result;
try {
move = new MoveMethod(
client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath),
mOverwrite
);
int status = client.executeMethod(move, MOVE_READ_TIMEOUT, MOVE_CONNECTION_TIMEOUT);
// After finishing a chunked upload, we have to move the resulting file from uploads folder to files one,
// so this uri has to be customizable
Uri srcWebDavUri = moveChunkedFile ? client.getNewUploadsWebDavUri() : client.getNewFilesWebDavUri();
final MoveMethod move = new MoveMethod(
new URL(srcWebDavUri + WebdavUtils.encodePath(mSrcRemotePath)),
client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mTargetRemotePath),
mOverwrite);
if (moveChunkedFile) {
move.addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp);
move.addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, String.valueOf(mFileLength));
}
move.setReadTimeout(MOVE_READ_TIMEOUT, TimeUnit.SECONDS);
move.setConnectionTimeout(MOVE_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
final int status = client.executeHttpMethod(move);
/// process response
if (status == HttpStatus.SC_MULTI_STATUS) {
result = processPartialError(move);
if(isSuccess(status)) {
result = new RemoteOperationResult<>(ResultCode.OK);
} else if (status == HttpConstants.HTTP_PRECONDITION_FAILED && !mOverwrite) {
} else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) {
result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
result = new RemoteOperationResult<>(ResultCode.INVALID_OVERWRITE);
client.exhaustResponse(move.getResponseBodyAsStream());
/// for other errors that could be explicitly handled, check first:
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
} else {
result = new RemoteOperationResult(isSuccess(status), move);
result = new RemoteOperationResult<>(move);
client.exhaustResponse(move.getResponseBodyAsStream());
}
@ -141,67 +147,15 @@ public class MoveRemoteFileOperation extends RemoteOperation {
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log.e(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
result.getLogMessage(), e);
} finally {
if (move != null)
move.releaseConnection();
}
return result;
}
/**
* Analyzes a multistatus response from the OC server to generate an appropriate result.
* <p>
* In WebDAV, a MOVE request on collections (folders) can be PARTIALLY successful: some
* children are moved, some other aren't.
* <p>
* According to the WebDAV specification, a multistatus response SHOULD NOT include partial
* successes (201, 204) nor for descendants of already failed children (424) in the response
* entity. But SHOULD NOT != MUST NOT, so take carefully.
*
* @param move Move operation just finished with a multistatus response
* @throws IOException If the response body could not be parsed
* @throws DavException If the status code is other than MultiStatus or if obtaining
* the response XML document fails
* @return A result for the {@link MoveRemoteFileOperation} caller
*/
private RemoteOperationResult processPartialError(MoveMethod move)
throws IOException, DavException {
// Adding a list of failed descendants to the result could be interesting; or maybe not.
// For the moment, let's take the easy way.
/// check that some error really occurred
MultiStatusResponse[] responses = move.getResponseBodyAsMultiStatus().getResponses();
Status[] status = null;
boolean failFound = false;
for (int i = 0; i < responses.length && !failFound; i++) {
status = responses[i].getStatus();
failFound = (
status != null &&
status.length > 0 &&
status[0].getStatusCode() > 299
);
}
RemoteOperationResult result;
if (failFound) {
result = new RemoteOperationResult(ResultCode.PARTIAL_MOVE_DONE);
} else {
result = new RemoteOperationResult(true, move);
}
return result;
}
protected boolean isSuccess(int status) {
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
return status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT;
}
}

View File

@ -23,20 +23,20 @@
*/
package com.owncloud.android.lib.resources.files;
import java.util.ArrayList;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import static com.owncloud.android.lib.common.http.methods.webdav.DavConstants.DEPTH_0;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Remote operation performing the read a file from the ownCloud server.
@ -45,7 +45,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
* @author masensio
*/
public class ReadRemoteFileOperation extends RemoteOperation {
public class ReadRemoteFileOperation extends RemoteOperation<RemoteFile> {
private static final String TAG = ReadRemoteFileOperation.class.getSimpleName();
private static final int SYNC_READ_TIMEOUT = 40000;
@ -53,7 +53,6 @@ public class ReadRemoteFileOperation extends RemoteOperation {
private String mRemotePath;
/**
* Constructor
*
@ -69,51 +68,41 @@ public class ReadRemoteFileOperation extends RemoteOperation {
* @param client Client object to communicate with the remote ownCloud server.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
PropFindMethod propfind = null;
RemoteOperationResult result = null;
protected RemoteOperationResult<RemoteFile> run(OwnCloudClient client) {
PropfindMethod propfind;
RemoteOperationResult<RemoteFile> result;
/// take the duty of check the server for the current state of the file there
try {
// remote request
propfind = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath),
WebdavUtils.getFilePropSet(), // PropFind Properties
DavConstants.DEPTH_0);
int status;
status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT);
propfind = new PropfindMethod(new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)),
DEPTH_0,
DavUtils.getAllPropset());
boolean isSuccess = (
status == HttpStatus.SC_MULTI_STATUS ||
status == HttpStatus.SC_OK
);
if (isSuccess) {
// Parse response
MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
WebdavEntry we = new WebdavEntry(resp.getResponses()[0],
client.getWebdavUri().getPath());
RemoteFile remoteFile = new RemoteFile(we);
ArrayList<Object> files = new ArrayList<Object>();
files.add(remoteFile);
propfind.setReadTimeout(SYNC_READ_TIMEOUT, TimeUnit.SECONDS);
propfind.setConnectionTimeout(SYNC_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
final int status = client.executeHttpMethod(propfind);
// Result of the operation
result = new RemoteOperationResult(true, propfind);
result.setData(files);
if (status == HttpConstants.HTTP_MULTI_STATUS
|| status == HttpConstants.HTTP_OK) {
final RemoteFile file = new RemoteFile(propfind.getRoot(), client.getCredentials().getUsername());
result = new RemoteOperationResult<>(OK);
result.setData(file);
} else {
result = new RemoteOperationResult(false, propfind);
result = new RemoteOperationResult<>(propfind);
client.exhaustResponse(propfind.getResponseBodyAsStream());
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
e.printStackTrace();
Log_OC.e(TAG, "Synchronizing file " + mRemotePath + ": " + result.getLogMessage(),
result.getException());
} finally {
if (propfind != null)
propfind.releaseConnection();
}
return result;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,33 +24,36 @@
package com.owncloud.android.lib.resources.files;
import java.util.ArrayList;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.DavConstants;
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.net.URL;
import java.util.ArrayList;
import at.bitfire.dav4android.Response;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Remote operation performing the read of remote file or folder in the ownCloud server.
*
* @author David A. Velasco
* @author masensio
* @author David González Verdugo
*/
public class ReadRemoteFolderOperation extends RemoteOperation {
public class ReadRemoteFolderOperation extends RemoteOperation<ArrayList<RemoteFile>> {
private static final String TAG = ReadRemoteFolderOperation.class.getSimpleName();
private String mRemotePath;
private ArrayList<Object> mFolderAndFiles;
/**
* Constructor
@ -67,110 +70,60 @@ public class ReadRemoteFolderOperation extends RemoteOperation {
* @param client Client object to communicate with the remote ownCloud server.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
PropFindMethod query = null;
protected RemoteOperationResult<ArrayList<RemoteFile>> run(OwnCloudClient client) {
RemoteOperationResult<ArrayList<RemoteFile>> result = null;
try {
// remote request
query = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath),
WebdavUtils.getAllPropSet(), // PropFind Properties
DavConstants.DEPTH_1);
int status = client.executeMethod(query);
PropfindMethod propfindMethod = new PropfindMethod(
new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)),
DavConstants.DEPTH_1,
DavUtils.getAllPropset());
// check and process response
boolean isSuccess = (
status == HttpStatus.SC_MULTI_STATUS ||
status == HttpStatus.SC_OK
);
if (isSuccess) {
// get data from remote folder
MultiStatus dataInServer = query.getResponseBodyAsMultiStatus();
readData(dataInServer, client);
client.setFollowRedirects(true);
int status = client.executeHttpMethod(propfindMethod);
if (isSuccess(status)) {
ArrayList<RemoteFile> mFolderAndFiles = new ArrayList<>();
// parse data from remote folder
mFolderAndFiles.add(
new RemoteFile(propfindMethod.getRoot(), client.getCredentials().getUsername())
);
// loop to update every child
for (Response resource : propfindMethod.getMembers()) {
RemoteFile file = new RemoteFile(resource, client.getCredentials().getUsername());
mFolderAndFiles.add(file);
}
// Result of the operation
result = new RemoteOperationResult(true, query);
// Add data to the result
if (result.isSuccess()) {
result.setData(mFolderAndFiles);
}
} else {
// synchronization failed
result = new RemoteOperationResult(false, query);
result = new RemoteOperationResult<>(OK);
result.setData(mFolderAndFiles);
} else { // synchronization failed
result = new RemoteOperationResult<> (propfindMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
} finally {
if (query != null)
query.releaseConnection(); // let the connection available for other methods
if (result.isSuccess()) {
Log_OC.i(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage());
} else {
if (result.isException()) {
Log_OC.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage(),
result.getException());
result.getException());
} else {
Log_OC.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage());
}
}
}
return result;
}
public boolean isMultiStatus(int status) {
return (status == HttpStatus.SC_MULTI_STATUS);
}
/**
* Read the data retrieved from the server about the contents of the target folder
*
* @param remoteData Full response got from the server with the data of the target
* folder and its direct children.
* @param client Client instance to the remote server where the data were
* retrieved.
* @return
*/
private void readData(MultiStatus remoteData, OwnCloudClient client) {
mFolderAndFiles = new ArrayList<Object>();
// parse data from remote folder
WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0],
client.getWebdavUri().getPath());
mFolderAndFiles.add(fillOCFile(we));
// loop to update every child
RemoteFile remoteFile = null;
for (int i = 1; i < remoteData.getResponses().length; ++i) {
/// new OCFile instance with the data from the server
we = new WebdavEntry(remoteData.getResponses()[i], client.getWebdavUri().getPath());
remoteFile = fillOCFile(we);
mFolderAndFiles.add(remoteFile);
}
}
/**
* Creates and populates a new {@link RemoteFile} object with the data read from the server.
*
* @param we WebDAV entry read from the server for a WebDAV resource (remote file or folder).
* @return New OCFile instance representing the remote resource described by we.
*/
private RemoteFile fillOCFile(WebdavEntry we) {
RemoteFile file = new RemoteFile(we.decodedPath());
file.setCreationTimestamp(we.createTimestamp());
file.setLength(we.contentLength());
file.setMimeType(we.contentType());
file.setModifiedTimestamp(we.modifiedTimestamp());
file.setEtag(we.etag());
file.setPermissions(we.permissions());
file.setRemoteId(we.remoteId());
file.setSize(we.size());
file.setQuotaUsedBytes(we.quotaUsedBytes());
file.setQuotaAvailableBytes(we.quotaAvailableBytes());
file.setPrivateLink(we.privateLink());
return file;
private boolean isSuccess(int status) {
return status == HttpConstants.HTTP_MULTI_STATUS ||
status == HttpConstants.HTTP_OK;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,18 +24,36 @@
package com.owncloud.android.lib.resources.files;
import java.io.Serializable;
import java.math.BigDecimal;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import com.owncloud.android.lib.common.network.WebdavEntry;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.Response;
import at.bitfire.dav4android.property.CreationDate;
import at.bitfire.dav4android.property.GetContentLength;
import at.bitfire.dav4android.property.GetContentType;
import at.bitfire.dav4android.property.GetETag;
import at.bitfire.dav4android.property.GetLastModified;
import at.bitfire.dav4android.property.QuotaAvailableBytes;
import at.bitfire.dav4android.property.QuotaUsedBytes;
import at.bitfire.dav4android.property.owncloud.OCId;
import at.bitfire.dav4android.property.owncloud.OCPermissions;
import at.bitfire.dav4android.property.owncloud.OCPrivatelink;
import at.bitfire.dav4android.property.owncloud.OCSize;
import okhttp3.HttpUrl;
import static com.owncloud.android.lib.common.OwnCloudClient.NEW_WEBDAV_FILES_PATH_4_0;
/**
* Contains the data of a Remote File from a WebDavEntry
*
* @author masensio
* @author Christian Schabesberger
*/
public class RemoteFile implements Parcelable, Serializable {
@ -156,7 +174,7 @@ public class RemoteFile implements Parcelable, Serializable {
/**
* Create new {@link RemoteFile} with given path.
* <p>
*
* The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'.
*
* @param path The remote path of the file.
@ -167,21 +185,52 @@ public class RemoteFile implements Parcelable, Serializable {
throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path);
}
mRemotePath = path;
mCreationTimestamp = 0;
mLength = 0;
mMimeType = "DIR";
mQuotaUsedBytes = BigDecimal.ZERO;
mQuotaAvailableBytes = BigDecimal.ZERO;
mPrivateLink = null;
}
public RemoteFile(WebdavEntry webdavEntry) {
this(webdavEntry.decodedPath());
this.setCreationTimestamp(webdavEntry.createTimestamp());
this.setLength(webdavEntry.contentLength());
this.setMimeType(webdavEntry.contentType());
this.setModifiedTimestamp(webdavEntry.modifiedTimestamp());
this.setEtag(webdavEntry.etag());
this.setPermissions(webdavEntry.permissions());
this.setRemoteId(webdavEntry.remoteId());
this.setSize(webdavEntry.size());
this.setQuotaUsedBytes(webdavEntry.quotaUsedBytes());
this.setQuotaAvailableBytes(webdavEntry.quotaAvailableBytes());
this.setPrivateLink(webdavEntry.privateLink());
public RemoteFile(final Response davResource, String userName) {
this(getRemotePathFromUrl(davResource.getHref(), userName));
final List<Property> properties = davResource.getProperties();
for(Property property : properties) {
if(property instanceof CreationDate)
this.setCreationTimestamp(
Long.parseLong(((CreationDate) property).getCreationDate()));
if(property instanceof GetContentLength)
this.setLength(((GetContentLength) property).getContentLength());
if(property instanceof GetContentType)
this.setMimeType(((GetContentType) property).getType());
if(property instanceof GetLastModified)
this.setModifiedTimestamp(((GetLastModified) property).getLastModified());
if(property instanceof GetETag)
this.setEtag(((GetETag) property).getETag());
if(property instanceof OCPermissions)
this.setPermissions(((OCPermissions) property).getPermission());
if(property instanceof OCId)
this.setRemoteId(((OCId) property).getId());
if(property instanceof OCSize)
this.setSize(((OCSize) property).getSize());
if(property instanceof QuotaUsedBytes)
this.setQuotaUsedBytes(
BigDecimal.valueOf(((QuotaUsedBytes) property).getQuotaUsedBytes()));
if(property instanceof QuotaAvailableBytes)
this.setQuotaAvailableBytes(
BigDecimal.valueOf(((QuotaAvailableBytes) property).getQuotaAvailableBytes()));
if(property instanceof OCPrivatelink)
this.setPrivateLink(((OCPrivatelink) property).getLink());
}
}
private static String getRemotePathFromUrl(HttpUrl url, String displayName) {
final String davPath = NEW_WEBDAV_FILES_PATH_4_0 + displayName;
final String pathToOc = url.encodedPath().split(davPath)[0];
return Uri.decode(url.encodedPath()).replace(pathToOc + davPath, "");
}
/**
@ -262,5 +311,4 @@ public class RemoteFile implements Parcelable, Serializable {
dest.writeSerializable(mQuotaAvailableBytes);
dest.writeString(mPrivateLink);
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,29 +24,33 @@
package com.owncloud.android.lib.resources.files;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.net.URL;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Remote operation performing the removal of a remote file or folder in the ownCloud server.
*
* @author David A. Velasco
* @author masensio
* @author David González Verdugo
*/
public class RemoveRemoteFileOperation extends RemoteOperation {
private static final String TAG = RemoveRemoteFileOperation.class.getSimpleName();
private static final int REMOVE_READ_TIMEOUT = 30000;
private static final int REMOVE_CONNECTION_TIMEOUT = 5000;
private String mRemotePath;
protected boolean removeChunksFolder = false;
/**
* Constructor
*
@ -63,30 +67,31 @@ public class RemoveRemoteFileOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
DeleteMethod delete = null;
RemoteOperationResult result;
try {
delete = new DeleteMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT);
Uri srcWebDavUri = removeChunksFolder ? client.getNewUploadsWebDavUri() : client.getNewFilesWebDavUri();
DeleteMethod deleteMethod = new DeleteMethod(
new URL(srcWebDavUri + WebdavUtils.encodePath(mRemotePath)));
int status = client.executeHttpMethod(deleteMethod);
result = isSuccess(status) ?
new RemoteOperationResult<>(OK) :
new RemoteOperationResult<>(deleteMethod);
delete.getResponseBodyAsString(); // exhaust the response, although not interesting
result = new RemoteOperationResult(
(delete.succeeded() || status == HttpStatus.SC_NOT_FOUND),
delete
);
Log_OC.i(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage(), e);
} finally {
if (delete != null)
delete.releaseConnection();
}
return result;
}
private boolean isSuccess(int status) {
return status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_NO_CONTENT;
}
}

View File

@ -24,17 +24,17 @@
package com.owncloud.android.lib.resources.files;
import android.os.RemoteException;
import java.io.File;
import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
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 com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
@ -57,7 +57,6 @@ public class RenameRemoteFileOperation extends RemoteOperation {
private String mNewName;
private String mNewRemotePath;
/**
* Constructor
*
@ -88,51 +87,48 @@ public class RenameRemoteFileOperation extends RemoteOperation {
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
LocalMoveMethod move = null;
OwnCloudVersion version = client.getOwnCloudVersion();
boolean versionWithForbiddenChars =
final OwnCloudVersion version = client.getOwnCloudVersion();
final boolean versionWithForbiddenChars =
(version != null && version.isVersionWithForbiddenCharacters());
boolean noInvalidChars = FileUtils.isValidPath(mNewRemotePath, versionWithForbiddenChars);
if (noInvalidChars) {
try {
if (mNewName.equals(mOldName)) {
return new RemoteOperationResult(ResultCode.OK);
}
if(!FileUtils.isValidPath(mNewRemotePath, versionWithForbiddenChars))
return new RemoteOperationResult<>(ResultCode.INVALID_CHARACTER_IN_NAME);
if (targetPathIsUsed(client)) {
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
}
move = new LocalMoveMethod(client.getWebdavUri() +
WebdavUtils.encodePath(mOldRemotePath),
client.getWebdavUri() + WebdavUtils.encodePath(mNewRemotePath));
client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
result = new RemoteOperationResult(move.succeeded(), move);
Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " +
result.getLogMessage()
);
client.exhaustResponse(move.getResponseBodyAsStream());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " +
((mNewRemotePath == null) ? mNewName : mNewRemotePath) + ": " +
result.getLogMessage(), e);
} finally {
if (move != null)
move.releaseConnection();
try {
if (mNewName.equals(mOldName)) {
return new RemoteOperationResult<>(ResultCode.OK);
}
} else {
result = new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME);
}
if (targetPathIsUsed(client)) {
return new RemoteOperationResult<>(ResultCode.INVALID_OVERWRITE);
}
return result;
final MoveMethod move = new MoveMethod(new URL(client.getNewFilesWebDavUri() +
WebdavUtils.encodePath(mOldRemotePath)),
client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mNewRemotePath), false);
move.setReadTimeout(RENAME_READ_TIMEOUT, TimeUnit.SECONDS);
move.setConnectionTimeout(RENAME_READ_TIMEOUT, TimeUnit.SECONDS);
final int status = client.executeHttpMethod(move);
final RemoteOperationResult result =
(status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT)
? new RemoteOperationResult<>(ResultCode.OK)
: new RemoteOperationResult<>(move);
Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " +
result.getLogMessage()
);
client.exhaustResponse(move.getResponseBodyAsStream());
return result;
} catch (Exception e) {
final RemoteOperationResult result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " +
((mNewRemotePath == null) ? mNewName : mNewRemotePath) + ": " +
result.getLogMessage(), e);
return result;
}
}
/**
@ -146,27 +142,4 @@ public class RenameRemoteFileOperation extends RemoteOperation {
RemoteOperationResult exists = existenceCheckRemoteOperation.run(client);
return exists.isSuccess();
}
/**
* Move operation
*/
private class LocalMoveMethod extends DavMethodBase {
public LocalMoveMethod(String uri, String dest) {
super(uri);
addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest));
}
@Override
public String getName() {
return "MOVE";
}
@Override
protected boolean isSuccess(int status) {
return status == 201 || status == 204;
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,46 +24,39 @@
package com.owncloud.android.lib.resources.files;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.FileRequestEntity;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod;
import com.owncloud.android.lib.common.network.FileRequestBody;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.File;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import okhttp3.MediaType;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Remote operation performing the upload of a remote file to the ownCloud server.
*
* @author David A. Velasco
* @author masensio
* @author David González Verdugo
*/
public class UploadRemoteFileOperation extends RemoteOperation {
private static final String TAG = UploadRemoteFileOperation.class.getSimpleName();
protected static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
protected static final String OC_X_OC_MTIME_HEADER = "X-OC-Mtime";
protected static final String IF_MATCH_HEADER = "If-Match";
protected String mLocalPath;
protected String mRemotePath;
protected String mMimeType;
@ -74,7 +67,7 @@ public class UploadRemoteFileOperation extends RemoteOperation {
protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
protected RequestEntity mEntity = null;
protected FileRequestBody mFileRequestBody = null;
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType,
String fileLastModifTimestamp) {
@ -92,80 +85,69 @@ public class UploadRemoteFileOperation extends RemoteOperation {
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
DefaultHttpMethodRetryHandler oldRetryHandler =
(DefaultHttpMethodRetryHandler) client.getParams().getParameter(HttpMethodParams.RETRY_HANDLER);
RemoteOperationResult result;
try {
// prevent that uploads are retried automatically by network library
client.getParams().setParameter(
HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(0, false)
);
mPutMethod = new PutMethod(
new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)));
mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
mPutMethod.setRetryOnConnectionFailure(false);
if (mCancellationRequested.get()) {
// the operation was cancelled before getting it's turn to be executed in the queue of uploads
result = new RemoteOperationResult(new OperationCancelledException());
result = new RemoteOperationResult<>(new OperationCancelledException());
} else {
// perform the upload
result = uploadFile(client);
Log_OC.i(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " +
result.getLogMessage());
}
} catch (Exception e) {
if (mPutMethod != null && mPutMethod.isAborted()) {
result = new RemoteOperationResult(new OperationCancelledException());
result = new RemoteOperationResult<>(new OperationCancelledException());
Log_OC.e(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " +
result.getLogMessage(), new OperationCancelledException());
} else {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + ": " +
result.getLogMessage(), e);
}
} finally {
// reset previous retry handler
client.getParams().setParameter(
HttpMethodParams.RETRY_HANDLER,
oldRetryHandler
);
}
return result;
}
public boolean isSuccess(int status) {
return ((status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED ||
status == HttpStatus.SC_NO_CONTENT));
}
protected RemoteOperationResult<? extends Object> uploadFile(OwnCloudClient client) throws Exception {
protected RemoteOperationResult uploadFile(OwnCloudClient client) throws IOException {
int status;
RemoteOperationResult result;
try {
File f = new File(mLocalPath);
mEntity = new FileRequestEntity(f, mMimeType);
synchronized (mDataTransferListeners) {
((ProgressiveDataTransferer)mEntity)
.addDatatransferProgressListeners(mDataTransferListeners);
}
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(f.length()));
File fileToUpload = new File(mLocalPath);
mPutMethod.addRequestHeader(OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp);
MediaType mediaType = MediaType.parse(mMimeType);
mPutMethod.setRequestEntity(mEntity);
status = client.executeMethod(mPutMethod);
mFileRequestBody = new FileRequestBody(fileToUpload, mediaType);
result = new RemoteOperationResult(
isSuccess(status),
mPutMethod
);
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
} finally {
mPutMethod.releaseConnection(); // let the connection available for other methods
synchronized (mDataTransferListeners) {
mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners);
}
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(HttpConstants.IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
mPutMethod.addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, String.valueOf(fileToUpload.length()));
mPutMethod.addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp);
mPutMethod.setRequestBody(mFileRequestBody);
int status = client.executeHttpMethod(mPutMethod);
if (isSuccess(status)) {
return new RemoteOperationResult<>(OK);
} else { // synchronization failed
return new RemoteOperationResult<>(mPutMethod);
}
return result;
}
public Set<OnDatatransferProgressListener> getDataTransferListeners() {
@ -176,8 +158,8 @@ public class UploadRemoteFileOperation extends RemoteOperation {
synchronized (mDataTransferListeners) {
mDataTransferListeners.add(listener);
}
if (mEntity != null) {
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener);
if (mFileRequestBody != null) {
mFileRequestBody.addDatatransferProgressListener(listener);
}
}
@ -185,8 +167,8 @@ public class UploadRemoteFileOperation extends RemoteOperation {
synchronized (mDataTransferListeners) {
mDataTransferListeners.remove(listener);
}
if (mEntity != null) {
((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener);
if (mFileRequestBody != null) {
mFileRequestBody.removeDatatransferProgressListener(listener);
}
}
@ -198,4 +180,8 @@ public class UploadRemoteFileOperation extends RemoteOperation {
}
}
public boolean isSuccess(int status) {
return ((status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_CREATED ||
status == HttpConstants.HTTP_NO_CONTENT));
}
}

View File

@ -0,0 +1,138 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files.chunks;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod;
import com.owncloud.android.lib.common.network.ChunkFromFileRequestBody;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import static com.owncloud.android.lib.common.http.HttpConstants.IF_MATCH_HEADER;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Remote operation performing the chunked upload of a remote file to the ownCloud server.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation {
private static final int LAST_CHUNK_TIMEOUT = 900000; //15 mins.
public static final long CHUNK_SIZE = 1024000;
private static final String TAG = ChunkedUploadRemoteFileOperation.class.getSimpleName();
private String mTransferId;
public ChunkedUploadRemoteFileOperation(String transferId, String localPath, String remotePath, String mimeType,
String requiredEtag, String fileLastModifTimestamp) {
super(localPath, remotePath, mimeType, requiredEtag, fileLastModifTimestamp);
mTransferId = transferId;
}
@Override
protected RemoteOperationResult uploadFile(OwnCloudClient client) throws Exception {
int status;
RemoteOperationResult result = null;
FileChannel channel;
RandomAccessFile raf;
File fileToUpload = new File(mLocalPath);
MediaType mediaType = MediaType.parse(mMimeType);
raf = new RandomAccessFile(fileToUpload, "r");
channel = raf.getChannel();
mFileRequestBody = new ChunkFromFileRequestBody(fileToUpload, mediaType, channel, CHUNK_SIZE);
synchronized (mDataTransferListeners) {
mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners);
}
long offset = 0;
String uriPrefix = client.getNewUploadsWebDavUri() + FileUtils.PATH_SEPARATOR + String.valueOf(mTransferId);
long totalLength = fileToUpload.length();
long chunkCount = (long) Math.ceil((double) totalLength / CHUNK_SIZE);
for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++, offset += CHUNK_SIZE) {
mPutMethod = new PutMethod(
new URL(uriPrefix + FileUtils.PATH_SEPARATOR + chunkIndex)
);
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\"");
}
((ChunkFromFileRequestBody) mFileRequestBody).setOffset(offset);
if (mCancellationRequested.get()) {
result = new RemoteOperationResult<>(new OperationCancelledException());
break;
} else {
if (chunkIndex == chunkCount - 1) {
// Added a high timeout to the last chunk due to when the last chunk
// arrives to the server with the last PUT, all chunks get assembled
// within that PHP request, so last one takes longer.
mPutMethod.setReadTimeout(LAST_CHUNK_TIMEOUT, TimeUnit.MILLISECONDS);
}
mPutMethod.setRequestBody(mFileRequestBody);
status = client.executeHttpMethod(mPutMethod);
Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath +
", chunk index " + chunkIndex + ", count " + chunkCount +
", HTTP result status " + status);
if (isSuccess(status)) {
result = new RemoteOperationResult<>(OK);
} else {
result = new RemoteOperationResult<>(mPutMethod);
break;
}
}
}
if (channel != null)
channel.close();
if (raf != null)
raf.close();
return result;
}
}

View File

@ -0,0 +1,45 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files.chunks;
import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation;
/**
* Remote operation performing the creation of a new folder to save chunks during an upload to the ownCloud server.
*
* @author David González Verdugo
*/
public class CreateRemoteChunkFolderOperation extends CreateRemoteFolderOperation {
/**
* Constructor
*
* @param remotePath Full path to the new directory to create in the remote server.
* @param createFullPath 'True' means that all the ancestor folders should be created.
*/
public CreateRemoteChunkFolderOperation(String remotePath, boolean createFullPath) {
super(remotePath, createFullPath);
createChunksFolder = true;
}
}

View File

@ -0,0 +1,50 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files.chunks;
import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation;
/**
* Remote operation to move the file built from chunks after uploading it
*
* @author David González Verdugo
*/
public class MoveRemoteChunksFileOperation extends MoveRemoteFileOperation {
/**
* Constructor.
*
* @param srcRemotePath Remote path of the file/folder to move.
* @param targetRemotePath Remove path desired for the file/folder after moving it.
* @param overwrite
*/
public MoveRemoteChunksFileOperation(String srcRemotePath, String targetRemotePath, boolean overwrite,
String fileLastModifTimestamp, long fileLength) {
super(srcRemotePath, targetRemotePath, overwrite);
moveChunkedFile = true;
mFileLastModifTimestamp = fileLastModifTimestamp;
mFileLength = fileLength;
}
}

View File

@ -0,0 +1,41 @@
/* ownCloud Android Library is available under MIT license
* @author David González Verdugo
* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.files.chunks;
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
public class RemoveRemoteChunksFolderOperation extends RemoveRemoteFileOperation {
/**
* Constructor
*
* @param remotePath RemotePath of the remote file or folder to remove from the server
*/
public RemoveRemoteChunksFolderOperation(String remotePath) {
super(remotePath);
removeChunksFolder = true;
}
}

View File

@ -2,7 +2,7 @@
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
* Copyright (C) 2018 ownCloud GmbH.
* 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
@ -30,20 +30,26 @@ package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
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.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import okhttp3.FormBody;
/**
* Creates a new share. This allows sharing with a user or group or as a link.
*
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
*/
public class CreateRemoteShareOperation extends RemoteOperation {
@ -180,38 +186,22 @@ public class CreateRemoteShareOperation extends RemoteOperation {
mPublicUpload = publicUpload;
}
public boolean isGettingShareDetails() {
return mGetShareDetails;
}
public void setGetShareDetails(boolean set) {
mGetShareDetails = set;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result;
int status;
PostMethod post = null;
protected RemoteOperationResult<ShareParserResult> run(OwnCloudClient client) {
RemoteOperationResult<ShareParserResult> result;
try {
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
// Post Method
post = new PostMethod(uriBuilder.build().toString());
post.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded; charset=utf-8"); // necessary for special characters
post.addParameter(PARAM_PATH, mRemoteFilePath);
post.addParameter(PARAM_SHARE_TYPE, Integer.toString(mShareType.getValue()));
post.addParameter(PARAM_SHARE_WITH, mShareWith);
FormBody.Builder formBodyBuilder = new FormBody.Builder()
.add(PARAM_PATH, mRemoteFilePath)
.add(PARAM_SHARE_TYPE, Integer.toString(mShareType.getValue()))
.add(PARAM_SHARE_WITH, mShareWith);
if (mName.length() > 0) {
post.addParameter(PARAM_NAME, mName);
formBodyBuilder.add(PARAM_NAME, mName);
}
if (mExpirationDateInMillis > 0) {
@ -219,25 +209,33 @@ public class CreateRemoteShareOperation extends RemoteOperation {
Calendar expirationDate = Calendar.getInstance();
expirationDate.setTimeInMillis(mExpirationDateInMillis);
String formattedExpirationDate = dateFormat.format(expirationDate.getTime());
post.addParameter(PARAM_EXPIRATION_DATE, formattedExpirationDate);
formBodyBuilder.add(PARAM_EXPIRATION_DATE, formattedExpirationDate);
}
if (mPublicUpload) {
post.addParameter(PARAM_PUBLIC_UPLOAD, Boolean.toString(true));
formBodyBuilder.add(PARAM_PUBLIC_UPLOAD, Boolean.toString(true));
}
if (mPassword != null && mPassword.length() > 0) {
post.addParameter(PARAM_PASSWORD, mPassword);
formBodyBuilder.add(PARAM_PASSWORD, mPassword);
}
if (OCShare.DEFAULT_PERMISSION != mPermissions) {
post.addParameter(PARAM_PERMISSIONS, Integer.toString(mPermissions));
formBodyBuilder.add(PARAM_PERMISSIONS, Integer.toString(mPermissions));
}
post.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
status = client.executeMethod(post);
PostMethod postMethod = new PostMethod(new URL(uriBuilder.build().toString()));
postMethod.setRequestBody(formBodyBuilder.build());
postMethod.setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8);
postMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeHttpMethod(postMethod);
if (isSuccess(status)) {
String response = post.getResponseBodyAsString();
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
@ -245,11 +243,13 @@ public class CreateRemoteShareOperation extends RemoteOperation {
parser.setOneOrMoreSharesRequired(true);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
result = parser.parse(postMethod.getResponseBodyAsString());
if (result.isSuccess() && mGetShareDetails) {
// TODO Use executeHttpMethod
// retrieve more info - POST only returns the index of the new share
OCShare emptyShare = (OCShare) result.getData().get(0);
OCShare emptyShare = result.getData().getShares().get(0);
GetRemoteShareOperation getInfo = new GetRemoteShareOperation(
emptyShare.getRemoteId()
);
@ -257,23 +257,17 @@ public class CreateRemoteShareOperation extends RemoteOperation {
}
} else {
result = new RemoteOperationResult(false, post);
result = new RemoteOperationResult<>(postMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while Creating New Share", e);
} finally {
if (post != null) {
post.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -29,18 +29,22 @@ package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import java.net.URL;
/**
* Get the data about a Share resource, known its remote ID.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class GetRemoteShareOperation extends RemoteOperation {
public class GetRemoteShareOperation extends RemoteOperation<ShareParserResult> {
private static final String TAG = GetRemoteShareOperation.class.getSimpleName();
@ -51,58 +55,45 @@ public class GetRemoteShareOperation extends RemoteOperation {
mRemoteId = remoteId;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status = -1;
RemoteOperationResult<ShareParserResult> result;
// Get Method
GetMethod get = null;
// Get the response
try {
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
uriBuilder.appendEncodedPath(Long.toString(mRemoteId));
get = new GetMethod(uriBuilder.build().toString());
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
GetMethod getMethod = new GetMethod(new URL(uriBuilder.build().toString()));
status = client.executeMethod(get);
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeHttpMethod(getMethod);
if (isSuccess(status)) {
String response = get.getResponseBodyAsString();
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
new ShareXMLParser()
);
parser.setOneOrMoreSharesRequired(true);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
result = parser.parse(getMethod.getResponseBodyAsString());
} else {
result = new RemoteOperationResult(false, get);
result = new RemoteOperationResult<>(getMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting remote shares ", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -31,17 +31,20 @@ package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URL;
import java.util.ArrayList;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Created by masensio on 08/10/2015.
*
@ -62,8 +65,12 @@ import java.util.ArrayList;
*
* Status codes:
* 100 - successful
*
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
*/
public class GetRemoteShareesOperation extends RemoteOperation{
public class GetRemoteShareesOperation extends RemoteOperation<ArrayList<JSONObject>> {
private static final String TAG = GetRemoteShareesOperation.class.getSimpleName();
@ -81,7 +88,6 @@ public class GetRemoteShareesOperation extends RemoteOperation{
private static final String VALUE_FORMAT = "json";
private static final String VALUE_ITEM_TYPE = "file"; // to get the server search for users / groups
// JSON Node names
private static final String NODE_OCS = "ocs";
private static final String NODE_DATA = "data";
@ -112,29 +118,27 @@ public class GetRemoteShareesOperation extends RemoteOperation{
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result;
int status;
GetMethod get = null;
protected RemoteOperationResult<ArrayList<JSONObject>> run(OwnCloudClient client) {
RemoteOperationResult<ArrayList<JSONObject>> result;
try{
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(OCS_ROUTE);
uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT);
uriBuilder.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE);
uriBuilder.appendQueryParameter(PARAM_SEARCH, mSearchString);
uriBuilder.appendQueryParameter(PARAM_PAGE, String.valueOf(mPage));
uriBuilder.appendQueryParameter(PARAM_PER_PAGE, String.valueOf(mPerPage));
Uri.Builder uriBuilder = requestUri.buildUpon()
.appendEncodedPath(OCS_ROUTE)
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE)
.appendQueryParameter(PARAM_SEARCH, mSearchString)
.appendQueryParameter(PARAM_PAGE, String.valueOf(mPage))
.appendQueryParameter(PARAM_PER_PAGE, String.valueOf(mPerPage));
// Get Method
get = new GetMethod(uriBuilder.build().toString());
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
GetMethod getMethod = new GetMethod(new URL(uriBuilder.build().toString()));
status = client.executeMethod(get);
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeHttpMethod(getMethod);
String response = getMethod.getResponseBodyAsString();
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
Log_OC.d(TAG, "Successful response: " + response);
// Parse the response
@ -157,7 +161,7 @@ public class GetRemoteShareesOperation extends RemoteOperation{
respPartialRemotes
};
ArrayList<Object> data = new ArrayList<Object>(); // For result data
ArrayList<JSONObject> data = new ArrayList<>(); // For result data
for (int i=0; i<6; i++) {
for(int j=0; j< jsonResults[i].length(); j++){
JSONObject jsonResult = jsonResults[i].getJSONObject(j);
@ -166,15 +170,13 @@ public class GetRemoteShareesOperation extends RemoteOperation{
}
}
// Result
result = new RemoteOperationResult(true, get);
result = new RemoteOperationResult<>(OK);
result.setData(data);
Log_OC.d(TAG, "*** Get Users or groups completed " );
} else {
result = new RemoteOperationResult(false, get);
String response = get.getResponseBodyAsString();
result = new RemoteOperationResult<>(getMethod);
Log_OC.e(TAG, "Failed response while getting users/groups from the server ");
if (response != null) {
Log_OC.e(TAG, "*** status code: " + status + "; response message: " + response);
@ -182,20 +184,15 @@ public class GetRemoteShareesOperation extends RemoteOperation{
Log_OC.e(TAG, "*** status code: " + status);
}
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting users/groups", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -30,20 +30,24 @@ package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import java.net.URL;
/**
* Provide a list shares for a specific file.
* The input is the full path of the desired file.
* The output is a list of everyone who has the file shared with them.
*
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
*/
public class GetRemoteSharesForFileOperation extends RemoteOperation {
public class GetRemoteSharesForFileOperation extends RemoteOperation<ShareParserResult> {
private static final String TAG = GetRemoteSharesForFileOperation.class.getSimpleName();
@ -73,63 +77,48 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result;
int status;
GetMethod get = null;
protected RemoteOperationResult<ShareParserResult> run(OwnCloudClient client) {
RemoteOperationResult<ShareParserResult> result;
try {
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
uriBuilder.appendQueryParameter(PARAM_PATH, mRemoteFilePath);
uriBuilder.appendQueryParameter(PARAM_RESHARES, String.valueOf(mReshares));
uriBuilder.appendQueryParameter(PARAM_SUBFILES, String.valueOf(mSubfiles));
// Get Method
get = new GetMethod(uriBuilder.build().toString());
GetMethod getMethod = new GetMethod(new URL(uriBuilder.build().toString()));
// Add Parameters to Get Method
get.setQueryString(new NameValuePair[]{
new NameValuePair(PARAM_PATH, mRemoteFilePath),
new NameValuePair(PARAM_RESHARES, String.valueOf(mReshares)),
new NameValuePair(PARAM_SUBFILES, String.valueOf(mSubfiles))
});
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
int status = client.executeHttpMethod(getMethod);
if (isSuccess(status)) {
String response = get.getResponseBodyAsString();
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
result = parser.parse(getMethod.getResponseBodyAsString());
if (result.isSuccess()) {
Log_OC.d(TAG, "Got " + result.getData().size() + " shares");
Log_OC.d(TAG, "Got " + result.getData().getShares().size() + " shares");
}
} else {
result = new RemoteOperationResult(false, get);
result = new RemoteOperationResult<>(getMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting shares", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -1,7 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author masensio
* @author David A. Velasco
* Copyright (C) 2016 ownCloud GmbH.
*
* 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
@ -29,45 +28,44 @@ package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import java.net.URL;
/**
* Get the data from the server about ALL the known shares owned by the requester.
*
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
*/
public class GetRemoteSharesOperation extends RemoteOperation {
private static final String TAG = GetRemoteSharesOperation.class.getSimpleName();
public GetRemoteSharesOperation() {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status = -1;
RemoteOperationResult result;
// Get Method
GetMethod get = null;
// Get the response
try {
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
get = new GetMethod(uriBuilder.build().toString());
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
GetMethod getMethod = new GetMethod(
new URL(client.getBaseUri() + ShareUtils.SHARING_API_PATH)
);
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeHttpMethod(getMethod);
if (isSuccess(status)) {
String response = get.getResponseBodyAsString();
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
@ -75,26 +73,19 @@ public class GetRemoteSharesOperation extends RemoteOperation {
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
result = parser.parse(getMethod.getResponseBodyAsString());
} else {
result = new RemoteOperationResult(false, get);
result = new RemoteOperationResult<>(getMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting remote shares ", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -30,15 +30,20 @@ package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
import java.net.URL;
/**
* Remove a share
*
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
*/
public class RemoveRemoteShareOperation extends RemoteOperation {
@ -55,15 +60,11 @@ public class RemoveRemoteShareOperation extends RemoteOperation {
public RemoveRemoteShareOperation(int remoteShareId) {
mRemoteShareId = remoteShareId;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result;
int status;
DeleteMethod delete = null;
try {
Uri requestUri = client.getBaseUri();
@ -71,39 +72,37 @@ public class RemoveRemoteShareOperation extends RemoteOperation {
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
uriBuilder.appendEncodedPath(String.valueOf(mRemoteShareId));
delete = new DeleteMethod(uriBuilder.build().toString());
DeleteMethod deleteMethod = new DeleteMethod(
new URL(uriBuilder.build().toString())
);
delete.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
deleteMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(delete);
int status = client.executeHttpMethod(deleteMethod);
if (isSuccess(status)) {
String response = delete.getResponseBodyAsString();
// Parse xml response and obtain the list of shares
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
new ShareXMLParser()
);
result = parser.parse(response);
result = parser.parse(deleteMethod.getResponseBodyAsString());
Log_OC.d(TAG, "Unshare " + mRemoteShareId + ": " + result.getLogMessage());
} else {
result = new RemoteOperationResult(false, delete);
result = new RemoteOperationResult<>(deleteMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Unshare Link Exception " + result.getLogMessage(), e);
} finally {
if (delete != null)
delete.releaseConnection();
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Unshare Link Exception " + result.getLogMessage(), e);
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -0,0 +1,46 @@
/* ownCloud Android Library is available under MIT license
* @author Christian Schabesberger
* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.shares;
import java.util.ArrayList;
public class ShareParserResult {
private ArrayList<OCShare> shares;
private String parserMessage;
public ShareParserResult(ArrayList<OCShare> shares, String parserMessage) {
this.shares = shares;
this.parserMessage = parserMessage;
}
public ArrayList<OCShare> getShares() {
return shares;
}
public String getParserMessage() {
return parserMessage;
}
}

View File

@ -1,6 +1,7 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* @author David González Verdugo
* @author Christian Schabesberger
* Copyright (C) 2018 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -66,13 +67,13 @@ public class ShareToRemoteOperationResultParser {
mServerBaseUri = serverBaseURi;
}
public RemoteOperationResult parse(String serverResponse) {
public RemoteOperationResult<ShareParserResult> parse(String serverResponse) {
if (serverResponse == null || serverResponse.length() == 0) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
}
RemoteOperationResult result;
ArrayList<Object> resultData = new ArrayList<Object>();
RemoteOperationResult<ShareParserResult> result;
final ArrayList<OCShare> resultData = new ArrayList<>();
try {
// Parse xml response and obtain the list of shares
@ -85,17 +86,16 @@ public class ShareToRemoteOperationResultParser {
if (mShareXmlParser.isSuccess()) {
if ((shares != null && shares.size() > 0) || !mOneOrMoreSharesRequired) {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.OK);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK);
if (shares != null) {
for (OCShare share : shares) {
resultData.add(share);
// build the share link if not in the response
// (needed for OC servers < 9.0.0, see ShareXMLParser.java#line256)
if (share.getShareType() == ShareType.PUBLIC_LINK &&
(share.getShareLink() == null ||
share.getShareLink().length() <= 0) &&
share.getToken().length() > 0
) {
if (share.getShareType() == ShareType.PUBLIC_LINK
&& (share.getShareLink() == null
|| share.getShareLink().length() <= 0)
&& share.getToken().length() > 0) {
if (mServerBaseUri != null) {
String sharingLinkPath = ShareUtils.getSharingLinkPath(mOwnCloudVersion);
share.setShareLink(mServerBaseUri + sharingLinkPath + share.getToken());
@ -105,43 +105,38 @@ public class ShareToRemoteOperationResultParser {
}
}
}
result.setData(resultData);
result.setData(new ShareParserResult(resultData, ""));
} else {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
Log_OC.e(TAG, "Successful status with no share in the response");
}
} else if (mShareXmlParser.isWrongParameter()){
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER);
resultData.add(mShareXmlParser.getMessage());
result.setData(resultData);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER);
result.setData(new ShareParserResult(null, mShareXmlParser.getMessage()));
} else if (mShareXmlParser.isNotFound()){
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND);
resultData.add(mShareXmlParser.getMessage());
result.setData(resultData);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND);
result.setData(new ShareParserResult(null, mShareXmlParser.getMessage()));
} else if (mShareXmlParser.isForbidden()) {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN);
resultData.add(mShareXmlParser.getMessage());
result.setData(resultData);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN);
result.setData(new ShareParserResult(null, mShareXmlParser.getMessage()));
} else {
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
}
} catch (XmlPullParserException e) {
Log_OC.e(TAG, "Error parsing response from server ", e);
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
} catch (IOException e) {
Log_OC.e(TAG, "Error reading response from server ", e);
result = new RemoteOperationResult(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.WRONG_SERVER_RESPONSE);
}
return result;
}
}

View File

@ -1,6 +1,6 @@
/* ownCloud Android Library is available under MIT license
* @author David A. Velasco
* Copyright (C) 2016 ownCloud GmbH.
*
* 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
@ -26,32 +26,32 @@
package com.owncloud.android.lib.resources.shares;
import android.net.Uri;
import android.util.Pair;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PutMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import okhttp3.FormBody;
/**
* Updates parameters of an existing Share resource, known its remote ID.
* <p/>
*
* Allow updating several parameters, triggering a request to the server per parameter.
*
* @author David A. Velasco
* @author David González Verdugo
*/
public class UpdateRemoteShareOperation extends RemoteOperation {
public class UpdateRemoteShareOperation extends RemoteOperation<ShareParserResult> {
private static final String TAG = GetRemoteShareOperation.class.getSimpleName();
@ -163,104 +163,77 @@ public class UpdateRemoteShareOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status;
/// prepare array of parameters to update
List<Pair<String, String>> parametersToUpdate = new ArrayList<>();
if (mName != null) {
parametersToUpdate.add(new Pair<>(PARAM_NAME, mName));
}
if (mPassword != null) {
parametersToUpdate.add(new Pair<>(PARAM_PASSWORD, mPassword));
}
if (mExpirationDateInMillis < 0) {
// clear expiration date
parametersToUpdate.add(new Pair<>(PARAM_EXPIRATION_DATE, ""));
} else if (mExpirationDateInMillis > 0) {
// set expiration date
DateFormat dateFormat = new SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.GERMAN);
Calendar expirationDate = Calendar.getInstance();
expirationDate.setTimeInMillis(mExpirationDateInMillis);
String formattedExpirationDate = dateFormat.format(expirationDate.getTime());
parametersToUpdate.add(new Pair<>(PARAM_EXPIRATION_DATE, formattedExpirationDate));
} // else, ignore - no update
if (mPublicUpload != null) {
parametersToUpdate.add(new Pair<>(PARAM_PUBLIC_UPLOAD, Boolean.toString(mPublicUpload)));
}
// IMPORTANT: permissions parameter needs to be updated after mPublicUpload parameter,
// otherwise they would be set always as 1 (READ) in the server when mPublicUpload was updated
if (mPermissions > 0) {
// set permissions
parametersToUpdate.add(new Pair<>(PARAM_PERMISSIONS, Integer.toString(mPermissions)));
}
/// perform required PUT requests
PutMethod put = null;
String uriString;
protected RemoteOperationResult<ShareParserResult> run(OwnCloudClient client) {
RemoteOperationResult<ShareParserResult> result;
try {
FormBody.Builder formBodyBuilder = new FormBody.Builder();
// Parameters to update
if (mName != null) {
formBodyBuilder.add(PARAM_NAME, mName);
}
if (mExpirationDateInMillis < 0) {
// clear expiration date
formBodyBuilder.add(PARAM_EXPIRATION_DATE, "");
} else if (mExpirationDateInMillis > 0) {
// set expiration date
DateFormat dateFormat = new SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.GERMAN);
Calendar expirationDate = Calendar.getInstance();
expirationDate.setTimeInMillis(mExpirationDateInMillis);
String formattedExpirationDate = dateFormat.format(expirationDate.getTime());
formBodyBuilder.add(PARAM_EXPIRATION_DATE, formattedExpirationDate);
} // else, ignore - no update
if (mPublicUpload != null) {
formBodyBuilder.add(PARAM_PUBLIC_UPLOAD, Boolean.toString(mPublicUpload));
}
// IMPORTANT: permissions parameter needs to be updated after mPublicUpload parameter,
// otherwise they would be set always as 1 (READ) in the server when mPublicUpload was updated
if (mPermissions > 0) {
// set permissions
formBodyBuilder.add(PARAM_PERMISSIONS, Integer.toString(mPermissions));
}
Uri requestUri = client.getBaseUri();
Uri.Builder uriBuilder = requestUri.buildUpon();
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
uriBuilder.appendEncodedPath(Long.toString(mRemoteId));
uriString = uriBuilder.build().toString();
for (Pair<String, String> parameter : parametersToUpdate) {
if (put != null) {
put.releaseConnection();
}
put = new PutMethod(uriString);
put.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
put.setRequestEntity(new StringRequestEntity(
parameter.first + "=" + parameter.second,
ENTITY_CONTENT_TYPE,
ENTITY_CHARSET
));
PutMethod putMethod = new PutMethod(new URL(uriBuilder.build().toString()));
status = client.executeMethod(put);
putMethod.setRequestBody(formBodyBuilder.build());
if (status == HttpStatus.SC_OK) {
String response = put.getResponseBodyAsString();
putMethod.setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8);
putMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
// Parse xml response
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(response);
int status = client.executeHttpMethod(putMethod);
} else {
result = new RemoteOperationResult(false, put);
}
if (!result.isSuccess() &&
!PARAM_NAME.equals(parameter.first)
// fail in "name" parameter will be ignored; requires OCX, will fail
// fails in previous versions
) {
break;
}
if (isSuccess(status)) {
// Parse xml response
ShareToRemoteOperationResultParser parser = new ShareToRemoteOperationResultParser(
new ShareXMLParser()
);
parser.setOwnCloudVersion(client.getOwnCloudVersion());
parser.setServerBaseUri(client.getBaseUri());
result = parser.parse(putMethod.getResponseBodyAsString());
} else {
result = new RemoteOperationResult<>(putMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Exception while updating remote share ", e);
if (put != null) {
put.releaseConnection();
}
} finally {
if (put != null) {
put.releaseConnection();
}
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while Creating New Share", e);
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -24,31 +24,35 @@
*
*/
package com.owncloud.android.lib.resources.status;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.json.JSONObject;
import java.util.ArrayList;
import java.net.URL;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Get the Capabilities from the server
*
* Save in Result.getData in a OCCapability object
*
* @author masensio
* @author David González Verdugo
*/
public class GetRemoteCapabilitiesOperation extends RemoteOperation {
public class GetRemoteCapabilitiesOperation extends RemoteOperation<OCCapability> {
private static final String TAG = GetRemoteCapabilitiesOperation.class.getSimpleName();
// OCS Routes
private static final String OCS_ROUTE = "ocs/v2.php/cloud/capabilities";
@ -115,10 +119,8 @@ public class GetRemoteCapabilitiesOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status;
GetMethod get = null;
protected RemoteOperationResult<OCCapability> run(OwnCloudClient client) {
RemoteOperationResult<OCCapability> result;
try {
Uri requestUri = client.getBaseUri();
@ -126,14 +128,14 @@ public class GetRemoteCapabilitiesOperation extends RemoteOperation {
uriBuilder.appendEncodedPath(OCS_ROUTE); // avoid starting "/" in this method
uriBuilder.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT);
// Get Method
get = new GetMethod(uriBuilder.build().toString());
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
GetMethod getMethod = new GetMethod(new URL(uriBuilder.build().toString()));
status = client.executeMethod(get);
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeHttpMethod(getMethod);
String response = getMethod.getResponseBodyAsString();
if(isSuccess(status)) {
String response = get.getResponseBodyAsString();
Log_OC.d(TAG, "Successful response: " + response);
// Parse the response
@ -148,7 +150,6 @@ public class GetRemoteCapabilitiesOperation extends RemoteOperation {
String message = respMeta.getString(PROPERTY_MESSAGE);
if (statusProp) {
ArrayList<Object> data = new ArrayList<Object>(); // For result data
OCCapability capability = new OCCapability();
// Add Version
if (respData.has(NODE_VERSION)) {
@ -254,20 +255,18 @@ public class GetRemoteCapabilitiesOperation extends RemoteOperation {
}
}
// Result
data.add(capability);
result = new RemoteOperationResult(true, get);
result.setData(data);
result = new RemoteOperationResult<>(OK);
result.setData(capability);
Log_OC.d(TAG, "*** Get Capabilities completed ");
} else {
result = new RemoteOperationResult(statusProp, statuscode, null, null);
result = new RemoteOperationResult<>(statuscode, message, null);
Log_OC.e(TAG, "Failed response while getting capabilities from the server ");
Log_OC.e(TAG, "*** status: " + statusProp + "; message: " + message);
}
} else {
result = new RemoteOperationResult(false, get);
String response = get.getResponseBodyAsString();
result = new RemoteOperationResult<>(getMethod);
Log_OC.e(TAG, "Failed response while getting capabilities from the server ");
if (response != null) {
Log_OC.e(TAG, "*** status code: " + status + "; response message: " + response);
@ -277,18 +276,13 @@ public class GetRemoteCapabilitiesOperation extends RemoteOperation {
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting capabilities", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,40 +24,41 @@
package com.owncloud.android.lib.resources.status;
import java.util.ArrayList;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Uri;
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.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Checks if the server is valid and if the server supports the Share API
*
* @author David A. Velasco
* @author masensio
* @author David González Verdugo
*/
public class GetRemoteStatusOperation extends RemoteOperation {
public class GetRemoteStatusOperation extends RemoteOperation<OwnCloudVersion> {
/**
* Maximum time to wait for a response from the server when the connection is being tested,
* in MILLISECONDs.
*/
public static final int TRY_CONNECTION_TIMEOUT = 5000;
public static final long TRY_CONNECTION_TIMEOUT = 5000;
private static final String TAG = GetRemoteStatusOperation.class.getSimpleName();
@ -66,7 +67,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
private static final String HTTPS_PREFIX = "https://";
private static final String HTTP_PREFIX = "http://";
private RemoteOperationResult mLatestResult;
private RemoteOperationResult<OwnCloudVersion> mLatestResult;
private Context mContext;
public GetRemoteStatusOperation(Context context) {
@ -75,20 +76,25 @@ public class GetRemoteStatusOperation extends RemoteOperation {
private boolean tryConnection(OwnCloudClient client) {
boolean retval = false;
GetMethod get = null;
String baseUrlSt = client.getBaseUri().toString();
try {
get = new GetMethod(baseUrlSt + OwnCloudClient.STATUS_PATH);
GetMethod getMethod = new GetMethod(new URL(baseUrlSt + OwnCloudClient.STATUS_PATH));
HttpParams params = get.getParams().getDefaultParams();
params.setParameter(HttpMethodParams.USER_AGENT,
OwnCloudClientManagerFactory.getUserAgent());
get.getParams().setDefaults(params);
getMethod.setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
getMethod.setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
client.setFollowRedirects(false);
boolean isRedirectToNonSecureConnection = false;
int status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
mLatestResult = new RemoteOperationResult((status == HttpStatus.SC_OK), get);
int status;
try {
status = client.executeHttpMethod(getMethod);
mLatestResult = isSuccess(status)
? new RemoteOperationResult<>(OK)
: new RemoteOperationResult<>(getMethod);
} catch (SSLException sslE) {
mLatestResult = new RemoteOperationResult(sslE);
return false;
}
String redirectedLocation = mLatestResult.getRedirectedLocation();
while (redirectedLocation != null && redirectedLocation.length() > 0
@ -98,61 +104,53 @@ public class GetRemoteStatusOperation extends RemoteOperation {
baseUrlSt.startsWith(HTTPS_PREFIX) &&
redirectedLocation.startsWith(HTTP_PREFIX)
);
get.releaseConnection();
get = new GetMethod(redirectedLocation);
status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
mLatestResult = new RemoteOperationResult(
(status == HttpStatus.SC_OK),
get
);
getMethod = new GetMethod(new URL(redirectedLocation));
getMethod.setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
getMethod.setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
status = client.executeHttpMethod(getMethod);
mLatestResult = new RemoteOperationResult<>(getMethod);
redirectedLocation = mLatestResult.getRedirectedLocation();
}
String response = get.getResponseBodyAsString();
if (status == HttpStatus.SC_OK) {
JSONObject json = new JSONObject(response);
if (!json.getBoolean(NODE_INSTALLED)) {
if (isSuccess(status)) {
JSONObject respJSON = new JSONObject(getMethod.getResponseBodyAsString());
if (!respJSON.getBoolean(NODE_INSTALLED)) {
mLatestResult = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
} else {
String version = json.getString(NODE_VERSION);
String version = respJSON.getString(NODE_VERSION);
OwnCloudVersion ocVersion = new OwnCloudVersion(version);
/// the version object will be returned even if the version is invalid, no error code;
/// every app will decide how to act if (ocVersion.isVersionValid() == false)
if (isRedirectToNonSecureConnection) {
mLatestResult = new RemoteOperationResult(
mLatestResult = new RemoteOperationResult<>(
RemoteOperationResult.ResultCode.
OK_REDIRECT_TO_NON_SECURE_CONNECTION
);
OK_REDIRECT_TO_NON_SECURE_CONNECTION);
} else {
mLatestResult = new RemoteOperationResult(
mLatestResult = new RemoteOperationResult<>(
baseUrlSt.startsWith(HTTPS_PREFIX) ?
RemoteOperationResult.ResultCode.OK_SSL :
RemoteOperationResult.ResultCode.OK_NO_SSL
);
RemoteOperationResult.ResultCode.OK_NO_SSL);
}
ArrayList<Object> data = new ArrayList<Object>();
data.add(ocVersion);
mLatestResult.setData(data);
mLatestResult.setData(ocVersion);
retval = true;
}
} else {
mLatestResult = new RemoteOperationResult(false, get);
mLatestResult = new RemoteOperationResult<>(getMethod);
}
} catch (JSONException e) {
mLatestResult = new RemoteOperationResult(
mLatestResult = new RemoteOperationResult<>(
RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
} catch (Exception e) {
mLatestResult = new RemoteOperationResult(e);
} finally {
if (get != null)
get.releaseConnection();
mLatestResult = new RemoteOperationResult<>(e);
}
if (mLatestResult.isSuccess()) {
@ -177,9 +175,9 @@ public class GetRemoteStatusOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
protected RemoteOperationResult<OwnCloudVersion> run(OwnCloudClient client) {
if (!isOnline()) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
}
String baseUriStr = client.getBaseUri().toString();
if (baseUriStr.startsWith(HTTP_PREFIX) || baseUriStr.startsWith(HTTPS_PREFIX)) {
@ -197,4 +195,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
return mLatestResult;
}
private boolean isSuccess(int status) {
return (status == HttpConstants.HTTP_OK);
}
}

View File

@ -1,7 +1,6 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -26,33 +25,32 @@
package com.owncloud.android.lib.resources.users;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Gets avatar about the user logged in, if available
* @author David A. Velasco
* @author David González Verdugo
*/
public class GetRemoteUserAvatarOperation extends RemoteOperation {
public class GetRemoteUserAvatarOperation extends RemoteOperation<GetRemoteUserAvatarOperation.ResultData> {
private static final String TAG = GetRemoteUserAvatarOperation.class.getSimpleName();
private static final String NON_OFFICIAL_AVATAR_PATH = "/index.php/avatar/";
private static final String IF_NONE_MATCH_HEADER = "If-None-Match";
/** Desired size in pixels of the squared image */
private int mDimension;
@ -63,67 +61,54 @@ public class GetRemoteUserAvatarOperation extends RemoteOperation {
*/
private String mCurrentEtag;
public GetRemoteUserAvatarOperation(int dimension, String currentEtag) {
mDimension = dimension;
mCurrentEtag = currentEtag;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
GetMethod get = null;
protected RemoteOperationResult<ResultData> run(OwnCloudClient client) {
GetMethod getMethod = null;
RemoteOperationResult<ResultData> result;
InputStream inputStream = null;
BufferedInputStream bis = null;
ByteArrayOutputStream bos = null;
try {
String uri =
client.getBaseUri() + NON_OFFICIAL_AVATAR_PATH +
client.getCredentials().getUsername() + "/" + mDimension;
;
Log_OC.d(TAG, "avatar URI: " + uri);
get = new GetMethod(uri);
/* Conditioned call is corrupting the input stream of the connection.
Seems that response with 304 is also including the avatar in the response body,
though it's forbidden by HTTPS specification. Besides, HTTPClient library
assumes there is nothing in the response body, but the bytes are read
by the next request, resulting in an exception due to a corrupt status line
final String url =
client.getBaseUri() + NON_OFFICIAL_AVATAR_PATH +
client.getCredentials().getUsername() + "/" + mDimension;
Log_OC.d(TAG, "avatar URI: " + url);
Maybe when we have a real API we can enable this again.
getMethod = new GetMethod(new URL(url));
if (mCurrentEtag != null && mCurrentEtag.length() > 0) {
get.addRequestHeader(IF_NONE_MATCH_HEADER, "\"" + mCurrentEtag + "\"");
}
*/
int status = client.executeHttpMethod(getMethod);
//get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeMethod(get);
if (isSuccess(status)) {
// find out size of file to read
int totalToTransfer = 0;
Header contentLength = get.getResponseHeader("Content-Length");
if (contentLength != null && contentLength.getValue().length() > 0) {
totalToTransfer = Integer.parseInt(contentLength.getValue());
String contentLength = getMethod.getResponseHeader(HttpConstants.CONTENT_LENGTH_HEADER);
if (contentLength != null && contentLength.length() > 0) {
totalToTransfer = Integer.parseInt(contentLength);
}
// find out MIME-type!
String mimeType;
Header contentType = get.getResponseHeader("Content-Type");
if (contentType == null || !contentType.getValue().startsWith("image")) {
String contentType = getMethod.getResponseHeader(HttpConstants.CONTENT_TYPE_HEADER);
if (contentType == null || !contentType.startsWith("image")) {
Log_OC.e(
TAG, "Not an image, failing with no avatar"
);
result = new RemoteOperationResult(
RemoteOperationResult.ResultCode.FILE_NOT_FOUND
);
result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.FILE_NOT_FOUND);
return result;
}
mimeType = contentType.getValue();
mimeType = contentType;
/// download will be performed to a buffer
inputStream = get.getResponseBodyAsStream();
inputStream = getMethod.getResponseBodyAsStream();
bis = new BufferedInputStream(inputStream);
bos = new ByteArrayOutputStream(totalToTransfer);
@ -137,29 +122,26 @@ public class GetRemoteUserAvatarOperation extends RemoteOperation {
// TODO check total bytes transferred?
// find out etag
String etag = WebdavUtils.getEtagFromResponse(get);
String etag = WebdavUtils.getEtagFromResponse(getMethod);
if (etag.length() == 0) {
Log_OC.w(TAG, "Could not read Etag from avatar");
}
// Result
result = new RemoteOperationResult(true, get);
ResultData resultData = new ResultData(bos.toByteArray(), mimeType, etag);
ArrayList<Object> data = new ArrayList<Object>();
data.add(resultData);
result.setData(data);
result = new RemoteOperationResult<>(OK);
result.setData(new ResultData(bos.toByteArray(), mimeType, etag));
} else {
result = new RemoteOperationResult(false, get);
client.exhaustResponse(get.getResponseBodyAsStream());
result = new RemoteOperationResult<>(getMethod);
client.exhaustResponse(getMethod.getResponseBodyAsStream());
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting OC user avatar", e);
} finally {
if (get != null) {
if (getMethod != null) {
try {
if (inputStream != null) {
client.exhaustResponse(inputStream);
@ -179,7 +161,6 @@ public class GetRemoteUserAvatarOperation extends RemoteOperation {
} catch (IOException o) {
Log_OC.e(TAG, "Unexpected exception closing output stream ", o);
}
get.releaseConnection();
}
}
@ -187,7 +168,7 @@ public class GetRemoteUserAvatarOperation extends RemoteOperation {
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
public static class ResultData {
@ -213,5 +194,4 @@ public class GetRemoteUserAvatarOperation extends RemoteOperation {
return mAvatarData;
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* 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
@ -24,26 +24,28 @@
package com.owncloud.android.lib.resources.users;
import java.util.ArrayList;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.json.JSONObject;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.json.JSONObject;
import java.net.URL;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* Gets information (id, display name, and e-mail address) about the user logged in.
*
* @author masensio
* @author David A. Velasco
* @author David González Verdugo
*/
public class GetRemoteUserInfoOperation extends RemoteOperation {
public class GetRemoteUserInfoOperation extends RemoteOperation<GetRemoteUserInfoOperation.UserInfo> {
private static final String TAG = GetRemoteUserInfoOperation.class.getSimpleName();
@ -61,22 +63,19 @@ public class GetRemoteUserInfoOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
int status = -1;
GetMethod get = null;
protected RemoteOperationResult<UserInfo> run(OwnCloudClient client) {
RemoteOperationResult<UserInfo> result;
//Get the user
try {
get = new GetMethod(client.getBaseUri() + OCS_ROUTE);
get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
status = client.executeMethod(get);
GetMethod getMethod = new GetMethod(new URL(client.getBaseUri() + OCS_ROUTE));
int status = client.executeHttpMethod(getMethod);
if (isSuccess(status)) {
String response = get.getResponseBodyAsString();
Log_OC.d(TAG, "Successful response");
// Parse the response
JSONObject respJSON = new JSONObject(response);
JSONObject respJSON = new JSONObject(getMethod.getResponseBodyAsString());
JSONObject respOCS = respJSON.getJSONObject(NODE_OCS);
JSONObject respData = respOCS.getJSONObject(NODE_DATA);
@ -85,41 +84,32 @@ public class GetRemoteUserInfoOperation extends RemoteOperation {
userInfo.mDisplayName = respData.getString(NODE_DISPLAY_NAME);
userInfo.mEmail = respData.getString(NODE_EMAIL);
// Result
result = new RemoteOperationResult(true, get);
// Username in result.data
ArrayList<Object> data = new ArrayList<Object>();
data.add(userInfo);
result.setData(data);
result = new RemoteOperationResult<>(OK);
result.setData(userInfo);
} else {
result = new RemoteOperationResult(false, get);
String response = get.getResponseBodyAsString();
result = new RemoteOperationResult<>(getMethod);
String response = getMethod.getResponseBodyAsString();
Log_OC.e(TAG, "Failed response while getting user information ");
if (response != null) {
if (getMethod != null) {
Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response);
} else {
Log_OC.e(TAG, "*** status code: " + status);
}
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
Log_OC.e(TAG, "Exception while getting OC user information", e);
} finally {
if (get != null) {
get.releaseConnection();
}
}
return result;
}
private boolean isSuccess(int status) {
return (status == HttpStatus.SC_OK);
return (status == HttpConstants.HTTP_OK);
}
public static class UserInfo {
public String mId = "";
public String mDisplayName = "";

View File

@ -28,42 +28,36 @@
package com.owncloud.android.lib.resources.users;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import java.net.URL;
import java.util.List;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.property.QuotaAvailableBytes;
import at.bitfire.dav4android.property.QuotaUsedBytes;
import static com.owncloud.android.lib.common.http.methods.webdav.DavConstants.DEPTH_0;
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
/**
* @author marcello
* @author David González Verdugo
*/
public class GetRemoteUserQuotaOperation extends RemoteOperation {
public class GetRemoteUserQuotaOperation extends RemoteOperation<GetRemoteUserQuotaOperation.RemoteQuota> {
static public class Quota {
// Not computed yet, e.g. external storage mounted but folder sizes need scanning
public static final int PENDING_FREE_QUOTA = -1;
// Storage not accessible, e.g. external storage with no API to ask for the free space
public static final int UNKNOWN_FREE_QUOTA = -2;
// Quota using all the storage
public static final int UNLIMITED_FREE_QUOTA = -3;
static public class RemoteQuota {
long mFree, mUsed, mTotal;
double mRelative;
public Quota(long free, long used, long total, double relative) {
public RemoteQuota(long free, long used, long total, double relative) {
mFree = free;
mUsed = used;
mTotal = total;
@ -90,45 +84,36 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation {
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
PropFindMethod query = null;
protected RemoteOperationResult<RemoteQuota> run(OwnCloudClient client) {
RemoteOperationResult<RemoteQuota> result = null;
try {
// remote request
query = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath),
WebdavUtils.getQuotaPropSet(),
DavConstants.DEPTH_0);
PropfindMethod propfindMethod = new PropfindMethod(
new URL(client.getNewFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)),
DEPTH_0,
DavUtils.getQuotaPropSet());
int status = client.executeMethod(query);
int status = client.executeHttpMethod(propfindMethod);
if (isSuccess(status)) {
// get data from remote folder
MultiStatus dataInServer = query.getResponseBodyAsMultiStatus();
Quota quota = readData(dataInServer, client);
RemoteQuota remoteQuota = readData(propfindMethod.getRoot().getProperties());
// Result of the operation
result = new RemoteOperationResult(true, query);
ArrayList<Object> data = new ArrayList<>();
data.add(quota);
result = new RemoteOperationResult<>(OK);
// Add data to the result
if (result.isSuccess()) {
result.setData(data);
result.setData(remoteQuota);
}
} else {
// synchronization failed
result = new RemoteOperationResult(false, query);
} else { // synchronization failed
result = new RemoteOperationResult<>(propfindMethod);
}
} catch (Exception e) {
result = new RemoteOperationResult(e);
result = new RemoteOperationResult<>(e);
} finally {
if (query != null)
query.releaseConnection(); // let the connection available for other methods
if (result.isSuccess()) {
Log_OC.i(TAG, "Get quota from " + mRemotePath + ": " + result.getLogMessage());
} else {
@ -145,46 +130,47 @@ public class GetRemoteUserQuotaOperation extends RemoteOperation {
}
private boolean isSuccess(int status) {
return status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK;
return status == HttpConstants.HTTP_MULTI_STATUS || status == HttpConstants.HTTP_OK;
}
/**
* Read the data retrieved from the server about the quota
*
* @param remoteData Full response got from the server with the data of the quota
* @param client Client instance to the remote server where the data were retrieved
* @return new Quota instance representing the data read from the server
* @param properties WebDAV properties containing quota data
* @return new {@link RemoteQuota} instance representing the data read from the server
*/
private Quota readData(MultiStatus remoteData, OwnCloudClient client) {
private RemoteQuota readData(List<Property> properties) {
long quotaAvailable = 0;
long quotaUsed = 0;
// parse data from remote folder
WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getWebdavUri().getPath());
for(Property property : properties) {
if(property instanceof QuotaAvailableBytes)
quotaAvailable = ((QuotaAvailableBytes) property).getQuotaAvailableBytes();
if(property instanceof QuotaUsedBytes)
quotaUsed = ((QuotaUsedBytes) property).getQuotaUsedBytes();
}
// If there's a special case, available bytes will contain a negative code
// If there's a special case, quota available will contain a negative code
// -1, PENDING: Not computed yet, e.g. external storage mounted but folder sizes need scanning
// -2, UNKNOWN: Storage not accessible, e.g. external storage with no API to ask for the free space
// -3, UNLIMITED: Quota using all the storage
if (we.quotaAvailableBytes().compareTo(new BigDecimal(1)) == -1) {
return new Quota(
we.quotaAvailableBytes().longValue(),
we.quotaUsedBytes().longValue(),
if (quotaAvailable < 0) {
return new RemoteQuota(
quotaAvailable,
quotaUsed,
0,
0
);
} else {
long totalQuota = quotaAvailable + quotaUsed;
double relativeQuota = (double)(quotaUsed * 100)/totalQuota;
double roundedRelativeQuota = Math.round(relativeQuota * 100)/100.0d;
BigDecimal totalQuota = we.quotaAvailableBytes().add(we.quotaUsedBytes());
BigDecimal relativeQuota = we.quotaUsedBytes()
.multiply(new BigDecimal(100))
.divide(totalQuota, 2, RoundingMode.HALF_UP);
return new Quota(
we.quotaAvailableBytes().longValue(),
we.quotaUsedBytes().longValue(),
totalQuota.longValue(),
relativeQuota.doubleValue()
return new RemoteQuota(
quotaAvailable,
quotaUsed,
totalQuota,
roundedRelativeQuota
);
}
}

View File

@ -43,4 +43,8 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

View File

@ -1,193 +0,0 @@
/* 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,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.test_project;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
import com.owncloud.android.lib.common.network.AdvancedSslSocketFactory;
/**
* SelfSignedConfidentSslSocketFactory allows to create SSL {@link Socket}s
* that accepts self-signed server certificates.
*
* WARNING: this SHOULD NOT be used in productive environments.
*
* @author David A. Velasco
*/
public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocketFactory {
//private SSLContext mSslContext = null;
private AdvancedSslSocketFactory mWrappedSslSocketFactory = null;
/**
* Constructor for SelfSignedConfidentSslSocketFactory.
* @throws GeneralSecurityException
*/
public SelfSignedConfidentSslSocketFactory() throws GeneralSecurityException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(
null,
new TrustManager[] { new SelfSignedConfidentX509TrustManager() },
null
);
mWrappedSslSocketFactory = new AdvancedSslSocketFactory(sslContext, null, null);
}
/**
* @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
*/
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return mWrappedSslSocketFactory.createSocket(host, port);
}
/**
* @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
*/
@Override
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
throws IOException, UnknownHostException {
return mWrappedSslSocketFactory.createSocket(host, port, clientHost, clientPort);
}
/**
* Attempts to get a new socket connection to the given host within the given time limit.
*
* @param host The host name/IP
* @param port The port on the host
* @param clientHost The local host name/IP to bind the socket to
* @param clientPort The port on the local machine
* @param params {@link HttpConnectionParams} HTTP connection parameters.
*
* @return Socket A new socket
*
* @throws IOException if an I/O error occurs while creating the socket
* @throws UnknownHostException if the IP address of the host cannot be determined
*/
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort,
HttpConnectionParams params) throws IOException, UnknownHostException,
ConnectTimeoutException {
return mWrappedSslSocketFactory.createSocket(host, port, localAddress, localPort, params);
}
/**
* @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
*/
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
throws IOException, UnknownHostException {
return mWrappedSslSocketFactory.createSocket(socket, host, port, autoClose);
}
public static class SelfSignedConfidentX509TrustManager implements X509TrustManager {
private X509TrustManager mStandardTrustManager = null;
public SelfSignedConfidentX509TrustManager()
throws NoSuchAlgorithmException, KeyStoreException, CertStoreException {
super();
TrustManagerFactory factory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init((KeyStore)null);
mStandardTrustManager = findX509TrustManager(factory);
}
/**
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
mStandardTrustManager.checkClientTrusted(chain, authType);
}
/**
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
* String authType)
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
if (chain != null && chain.length == 1) {
chain[0].checkValidity();
} else {
mStandardTrustManager.checkServerTrusted(chain, authType);
}
}
/**
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers() {
return mStandardTrustManager.getAcceptedIssuers();
}
/**
* 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
*/
private X509TrustManager findX509TrustManager(TrustManagerFactory factory)
throws CertStoreException {
TrustManager tms[] = factory.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
return (X509TrustManager) tms[i];
}
}
return null;
}
}
}

View File

@ -24,15 +24,6 @@
package com.owncloud.android.lib.test_project;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
@ -41,12 +32,8 @@ import android.util.Log;
import android.view.Menu;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientFactory;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation;
import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
@ -54,12 +41,18 @@ import com.owncloud.android.lib.resources.files.RemoteFile;
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadRemoteFileOperation;
import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation;
import com.owncloud.android.lib.resources.shares.GetRemoteSharesOperation;
import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.users.GetRemoteUserQuotaOperation;
import com.owncloud.android.lib.resources.users.GetRemoteUserAvatarOperation;
import com.owncloud.android.lib.resources.users.GetRemoteUserQuotaOperation;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Activity to test OC framework
@ -94,23 +87,7 @@ public class TestActivity extends Activity {
mUser = getString(R.string.username);
mPass = getString(R.string.password);
Protocol pr = Protocol.getProtocol("https");
if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) {
try {
ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory();
Protocol.registerProtocol(
"https",
new Protocol("https", psf, 443));
} catch (GeneralSecurityException e) {
Log.e(TAG, "Self-signed confident SSL context could not be loaded");
}
}
mClient = new OwnCloudClient(Uri.parse(mServerUri), NetworkUtils.getMultiThreadedConnManager());
mClient.setDefaultTimeouts(
OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT,
OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT);
mClient = new OwnCloudClient(Uri.parse(mServerUri));
mClient.setFollowRedirects(true);
mClient.setCredentials(
OwnCloudCredentialsFactory.newBasicCredentials(
@ -271,8 +248,8 @@ public class TestActivity extends Activity {
UploadRemoteFileOperation uploadOperation;
if ((new File(storagePath)).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
uploadOperation = new ChunkedUploadRemoteFileOperation(
storagePath, remotePath, mimeType, fileLastModifTimestamp
uploadOperation = new ChunkedUploadRemoteFileOperation("1",
storagePath, remotePath, mimeType, TAG, fileLastModifTimestamp
);
} else {
uploadOperation = new UploadRemoteFileOperation(

View File

@ -37,14 +37,13 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.files.CopyRemoteFileOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import com.owncloud.android.lib.test_project.TestActivity;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import java.io.File;
import java.security.GeneralSecurityException;
@ -373,7 +372,7 @@ public class CopyFileTest extends ActivityInstrumentationTestCase2<TestActivity>
false
);
result = copyOperation.execute(mClient);
assertTrue(result.getHttpCode() == HttpStatus.SC_CONFLICT);
assertTrue(result.getHttpCode() == HttpConstants.HTTP_CONFLICT);
// target location (renaming) has invalid characters
copyOperation = new CopyRemoteFileOperation(

View File

@ -29,8 +29,8 @@ import java.security.GeneralSecurityException;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.content.Context;
import android.net.Uri;
@ -43,7 +43,6 @@ import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.status.GetRemoteCapabilitiesOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
/**
* Class to test GetRemoteCapabilitiesOperation

View File

@ -29,9 +29,9 @@ import java.security.GeneralSecurityException;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.json.JSONException;
import org.json.JSONObject;
@ -43,7 +43,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import android.content.Context;
import android.net.Uri;
@ -184,11 +183,11 @@ public class GetShareesTest extends RemoteTest {
// search for sharees including wrong page values
getShareesOperation = new GetRemoteShareesOperation("a", 0, 50);
result = getShareesOperation.execute(mClient);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpConstants.HTTP_BAD_REQUEST);
getShareesOperation = new GetRemoteShareesOperation("a", 1, 0);
result = getShareesOperation.execute(mClient);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpConstants.HTTP_BAD_REQUEST);
}
/**
@ -237,11 +236,11 @@ public class GetShareesTest extends RemoteTest {
// search for sharees including wrong page values
getShareesOperation = new GetRemoteShareesOperation("@", 0, 50);
result = getShareesOperation.execute(mClient);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpConstants.HTTP_BAD_REQUEST);
getShareesOperation = new GetRemoteShareesOperation("@", 1, 0);
result = getShareesOperation.execute(mClient);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST);
assertTrue(!result.isSuccess() && result.getHttpCode() == HttpConstants.HTTP_BAD_REQUEST);
}
@Override

View File

@ -31,7 +31,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.users.GetRemoteUserAvatarOperation.ResultData;
import com.owncloud.android.lib.test_project.TestActivity;
import org.apache.commons.httpclient.HttpStatus;
/**
* Class to test {@link GetRemoteUserAvatarOperation}
@ -81,7 +81,7 @@ public class GetUserAvatarTest extends RemoteTest {
// request again, with the just received etag
result = mActivity.getUserAvatar(AVATAR_DIMENSION, etag);
assertFalse(result.isSuccess());
assertTrue(result.getHttpCode() == HttpStatus.SC_NOT_MODIFIED);
assertTrue(result.getHttpCode() == HttpConstants.HTTP_NOT_MODIFIED);
}
*/

View File

@ -29,9 +29,9 @@ import java.security.GeneralSecurityException;
import junit.framework.AssertionFailedError;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientFactory;
@ -41,7 +41,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import com.owncloud.android.lib.test_project.TestActivity;
import android.content.Context;
@ -373,7 +372,7 @@ public class MoveFileTest extends RemoteTest {
false
);
result = moveOperation.execute(mClient);
assertTrue(result.getHttpCode() == HttpStatus.SC_CONFLICT);
assertTrue(result.getHttpCode() == HttpConstants.HTTP_CONFLICT);
// target location (renaming) has invalid characters
moveOperation = new MoveRemoteFileOperation(

View File

@ -27,12 +27,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
@ -48,7 +48,6 @@ import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
/**
@ -314,7 +313,7 @@ public class OwnCloudClientTest extends AndroidTestCase {
DavConstants.DEPTH_0);
int status = client.executeMethod(propfind);
assertEquals("WebDAV request did not work on WebDAV URI",
HttpStatus.SC_MULTI_STATUS, status);
HttpConstants.HTTP_MULTI_STATUS, status);
} catch (IOException e) {
Log.e(TAG, "Exception in PROPFIND method execution", e);

View File

@ -25,8 +25,8 @@ package com.owncloud.android.lib.test_project.test;
import java.security.GeneralSecurityException;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.net.Uri;
import android.test.AndroidTestCase;

View File

@ -25,8 +25,8 @@ package com.owncloud.android.lib.test_project.test;
import java.security.GeneralSecurityException;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import android.net.Uri;
import android.test.AndroidTestCase;
@ -36,7 +36,6 @@ import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.SingleSessionManager;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.test_project.R;
import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory;
import junit.framework.AssertionFailedError;

Some files were not shown because too many files have changed in this diff Show More