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:
commit
2fdf724eab
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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/>
|
@ -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"
|
||||
|
@ -42,4 +42,8 @@ android {
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE.txt'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
@ -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"-->
|
||||
<!-->-->
|
||||
<!--</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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -100,5 +100,4 @@ public class OwnCloudClientManagerFactory {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -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 ... : ");
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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";
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
172
src/com/owncloud/android/lib/common/http/HttpClient.java
Normal file
172
src/com/owncloud/android/lib/common/http/HttpClient.java
Normal 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();
|
||||
}
|
||||
}
|
189
src/com/owncloud/android/lib/common/http/HttpConstants.java
Normal file
189
src/com/owncloud/android/lib/common/http/HttpConstants.java
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
120
src/com/owncloud/android/lib/common/network/FileRequestBody.java
Normal file
120
src/com/owncloud/android/lib/common/network/FileRequestBody.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -27,7 +27,6 @@ package com.owncloud.android.lib.common.network;
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
|
||||
public interface ProgressiveDataTransferer {
|
||||
|
||||
public void addDatatransferProgressListener (OnDatatransferProgressListener listener);
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
63
src/com/owncloud/android/lib/common/utils/RandomUtils.java
Normal file
63
src/com/owncloud/android/lib/common/utils/RandomUtils.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 = "";
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -43,4 +43,8 @@ android {
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE.txt'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user