Loading src/main/aidl/com/nextcloud/android/sso/aidl/IInputStreamService.aidl +6 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,11 @@ package com.nextcloud.android.sso.aidl; interface IInputStreamService { ParcelFileDescriptor performNextcloudRequestAndBodyStream(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor); ParcelFileDescriptor performNextcloudRequestAndBodyStream(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor); ParcelFileDescriptor performNextcloudRequest(in ParcelFileDescriptor input); ParcelFileDescriptor performNextcloudRequestAndBodyStreamV2(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor); ParcelFileDescriptor performNextcloudRequestV2(in ParcelFileDescriptor input); } src/main/java/com/nextcloud/android/sso/api/AidlNetworkRequest.java +150 −3 Original line number Diff line number Diff line Loading @@ -11,8 +11,8 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; import androidx.annotation.NonNull; import com.google.gson.Gson; import com.google.gson.internal.LinkedTreeMap; import com.nextcloud.android.sso.Constants; import com.nextcloud.android.sso.aidl.IInputStreamService; import com.nextcloud.android.sso.aidl.IThreadListener; Loading @@ -27,8 +27,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; import androidx.annotation.NonNull; import static com.nextcloud.android.sso.exceptions.SSOException.parseNextcloudCustomException; public class AidlNetworkRequest extends NetworkRequest { Loading Loading @@ -130,6 +134,31 @@ public class AidlNetworkRequest extends NetworkRequest { } } /** * The InputStreams needs to be closed after reading from it * * @param request {@link NextcloudRequest} request to be executed on server via Files app * @param requestBodyInputStream inputstream to be sent to the server * @return InputStream answer from server as InputStream * @throws Exception or SSOException */ public Response performNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception { ParcelFileDescriptor output = performAidlNetworkRequestV2(request, requestBodyInputStream); InputStream os = new ParcelFileDescriptor.AutoCloseInputStream(output); ExceptionResponse response = deserializeObjectV2(os); // Handle Remote Exceptions if (response.getException() != null) { if (response.getException().getMessage() != null) { throw parseNextcloudCustomException(response.getException()); } throw response.getException(); } return new Response(os, response.headers); } /** * The InputStreams needs to be closed after reading from it * Loading Loading @@ -218,10 +247,128 @@ public class AidlNetworkRequest extends NetworkRequest { return output; } /** * DO NOT CALL THIS METHOD DIRECTLY - use @link(performNetworkRequestV2) instead * * @param request * @return * @throws IOException */ private ParcelFileDescriptor performAidlNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws IOException, RemoteException, NextcloudApiNotRespondingException { // Check if we are on the main thread if (Looper.myLooper() == Looper.getMainLooper()) { throw new NetworkOnMainThreadException(); } // Wait for api to be initialized waitForApi(); // Log.d(TAG, request.url); request.setAccountName(getAccountName()); request.setToken(getAccountToken()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(request); oos.close(); baos.close(); InputStream is = new ByteArrayInputStream(baos.toByteArray()); ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is, new IThreadListener() { @Override public void onThreadFinished(Thread thread) { Log.d(TAG, "copy data from service finished"); } }); ParcelFileDescriptor requestBodyParcelFileDescriptor = null; if (requestBodyInputStream != null) { requestBodyParcelFileDescriptor = ParcelFileDescriptorUtil.pipeFrom(requestBodyInputStream, new IThreadListener() { @Override public void onThreadFinished(Thread thread) { Log.d(TAG, "copy data from service finished"); } }); } ParcelFileDescriptor output; if (requestBodyParcelFileDescriptor != null) { output = mService.performNextcloudRequestAndBodyStreamV2(input, requestBodyParcelFileDescriptor); } else { output = mService.performNextcloudRequestV2(input); } return output; } private static <T> T deserializeObject(InputStream is) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(is); T result = (T) ois.readObject(); return result; } private ExceptionResponse deserializeObjectV2(InputStream is) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(is); ArrayList<PlainHeader> headerList = new ArrayList<>(); Exception exception = (Exception) ois.readObject(); if (exception == null) { String headers = (String) ois.readObject(); ArrayList list = new Gson().fromJson(headers, ArrayList.class); for (Object o : list) { LinkedTreeMap treeMap = (LinkedTreeMap) o; headerList.add(new PlainHeader((String) treeMap.get("name"), (String) treeMap.get("value"))); } } return new ExceptionResponse(exception, headerList); } public class PlainHeader implements Serializable { private String name; private String value; PlainHeader(String name, String value) { this.name = name; this.value = value; } public String getName() { return name; } public String getValue() { return value; } private void writeObject(ObjectOutputStream oos) throws IOException{ oos.writeObject(name); oos.writeObject(value); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); value = (String) in.readObject(); } } private class ExceptionResponse { private Exception exception; private ArrayList<PlainHeader> headers; public ExceptionResponse(Exception exception, ArrayList<PlainHeader> headers) { this.exception = exception; this.headers = headers; } public Exception getException() { return exception; } } } src/main/java/com/nextcloud/android/sso/api/NetworkRequest.java +4 −2 Original line number Diff line number Diff line Loading @@ -4,14 +4,14 @@ import android.content.Context; import android.os.Looper; import android.util.Log; import androidx.annotation.NonNull; import com.nextcloud.android.sso.aidl.NextcloudRequest; import com.nextcloud.android.sso.helper.ExponentialBackoff; import com.nextcloud.android.sso.model.SingleSignOnAccount; import java.io.InputStream; import androidx.annotation.NonNull; public abstract class NetworkRequest { private static final String TAG = NetworkRequest.class.getCanonicalName(); Loading @@ -38,6 +38,8 @@ public abstract class NetworkRequest { protected abstract InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception; protected abstract Response performNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception; protected void connectApiWithBackoff() { new ExponentialBackoff(1000, 10000, 2, 5, Looper.getMainLooper(), () -> { connect(mAccount.type); Loading src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java +30 −1 Original line number Diff line number Diff line Loading @@ -119,6 +119,35 @@ public class NextcloudAPI { return networkRequest.performNetworkRequest(request, null); } public Response performRequestV2(final @NonNull Type type, NextcloudRequest request) throws Exception { Log.d(TAG, "performRequest() called with: type = [" + type + "], request = [" + request + "]"); Response result = null; Response response = performNetworkRequestV2(request); Reader targetReader = new InputStreamReader(response.getBody()); if (type != Void.class) { result = gson.fromJson(targetReader, type); if (result != null) { Log.d(TAG, result.toString()); } } return result; } /** * The InputStreams needs to be closed after reading from it * * @param request {@link NextcloudRequest} request to be executed on server via Files app * @return InputStream answer from server as InputStream * @throws Exception or SSOException */ public Response performNetworkRequestV2(NextcloudRequest request) throws Exception { return networkRequest.performNetworkRequestV2(request, null); } /* public static <T> T deserializeObjectAndCloseStream(InputStream is) throws IOException, ClassNotFoundException { Loading src/main/java/com/nextcloud/android/sso/api/Response.java 0 → 100644 +35 −0 Original line number Diff line number Diff line package com.nextcloud.android.sso.api; import java.io.InputStream; import java.util.ArrayList; import androidx.annotation.Nullable; public class Response { private InputStream body; private ArrayList<AidlNetworkRequest.PlainHeader> headers; public Response(InputStream inputStream, ArrayList<AidlNetworkRequest.PlainHeader> headers) { this.body = inputStream; this.headers = headers; } public ArrayList<AidlNetworkRequest.PlainHeader> getPlainHeaders() { return headers; } public InputStream getBody() { return body; } @Nullable public AidlNetworkRequest.PlainHeader getPlainHeader(String key) { for (AidlNetworkRequest.PlainHeader header: headers) { if (header.getName().equalsIgnoreCase(key)) { return header; } } return null; } } Loading
src/main/aidl/com/nextcloud/android/sso/aidl/IInputStreamService.aidl +6 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,11 @@ package com.nextcloud.android.sso.aidl; interface IInputStreamService { ParcelFileDescriptor performNextcloudRequestAndBodyStream(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor); ParcelFileDescriptor performNextcloudRequestAndBodyStream(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor); ParcelFileDescriptor performNextcloudRequest(in ParcelFileDescriptor input); ParcelFileDescriptor performNextcloudRequestAndBodyStreamV2(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor); ParcelFileDescriptor performNextcloudRequestV2(in ParcelFileDescriptor input); }
src/main/java/com/nextcloud/android/sso/api/AidlNetworkRequest.java +150 −3 Original line number Diff line number Diff line Loading @@ -11,8 +11,8 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; import androidx.annotation.NonNull; import com.google.gson.Gson; import com.google.gson.internal.LinkedTreeMap; import com.nextcloud.android.sso.Constants; import com.nextcloud.android.sso.aidl.IInputStreamService; import com.nextcloud.android.sso.aidl.IThreadListener; Loading @@ -27,8 +27,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; import androidx.annotation.NonNull; import static com.nextcloud.android.sso.exceptions.SSOException.parseNextcloudCustomException; public class AidlNetworkRequest extends NetworkRequest { Loading Loading @@ -130,6 +134,31 @@ public class AidlNetworkRequest extends NetworkRequest { } } /** * The InputStreams needs to be closed after reading from it * * @param request {@link NextcloudRequest} request to be executed on server via Files app * @param requestBodyInputStream inputstream to be sent to the server * @return InputStream answer from server as InputStream * @throws Exception or SSOException */ public Response performNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception { ParcelFileDescriptor output = performAidlNetworkRequestV2(request, requestBodyInputStream); InputStream os = new ParcelFileDescriptor.AutoCloseInputStream(output); ExceptionResponse response = deserializeObjectV2(os); // Handle Remote Exceptions if (response.getException() != null) { if (response.getException().getMessage() != null) { throw parseNextcloudCustomException(response.getException()); } throw response.getException(); } return new Response(os, response.headers); } /** * The InputStreams needs to be closed after reading from it * Loading Loading @@ -218,10 +247,128 @@ public class AidlNetworkRequest extends NetworkRequest { return output; } /** * DO NOT CALL THIS METHOD DIRECTLY - use @link(performNetworkRequestV2) instead * * @param request * @return * @throws IOException */ private ParcelFileDescriptor performAidlNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws IOException, RemoteException, NextcloudApiNotRespondingException { // Check if we are on the main thread if (Looper.myLooper() == Looper.getMainLooper()) { throw new NetworkOnMainThreadException(); } // Wait for api to be initialized waitForApi(); // Log.d(TAG, request.url); request.setAccountName(getAccountName()); request.setToken(getAccountToken()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(request); oos.close(); baos.close(); InputStream is = new ByteArrayInputStream(baos.toByteArray()); ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is, new IThreadListener() { @Override public void onThreadFinished(Thread thread) { Log.d(TAG, "copy data from service finished"); } }); ParcelFileDescriptor requestBodyParcelFileDescriptor = null; if (requestBodyInputStream != null) { requestBodyParcelFileDescriptor = ParcelFileDescriptorUtil.pipeFrom(requestBodyInputStream, new IThreadListener() { @Override public void onThreadFinished(Thread thread) { Log.d(TAG, "copy data from service finished"); } }); } ParcelFileDescriptor output; if (requestBodyParcelFileDescriptor != null) { output = mService.performNextcloudRequestAndBodyStreamV2(input, requestBodyParcelFileDescriptor); } else { output = mService.performNextcloudRequestV2(input); } return output; } private static <T> T deserializeObject(InputStream is) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(is); T result = (T) ois.readObject(); return result; } private ExceptionResponse deserializeObjectV2(InputStream is) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(is); ArrayList<PlainHeader> headerList = new ArrayList<>(); Exception exception = (Exception) ois.readObject(); if (exception == null) { String headers = (String) ois.readObject(); ArrayList list = new Gson().fromJson(headers, ArrayList.class); for (Object o : list) { LinkedTreeMap treeMap = (LinkedTreeMap) o; headerList.add(new PlainHeader((String) treeMap.get("name"), (String) treeMap.get("value"))); } } return new ExceptionResponse(exception, headerList); } public class PlainHeader implements Serializable { private String name; private String value; PlainHeader(String name, String value) { this.name = name; this.value = value; } public String getName() { return name; } public String getValue() { return value; } private void writeObject(ObjectOutputStream oos) throws IOException{ oos.writeObject(name); oos.writeObject(value); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); value = (String) in.readObject(); } } private class ExceptionResponse { private Exception exception; private ArrayList<PlainHeader> headers; public ExceptionResponse(Exception exception, ArrayList<PlainHeader> headers) { this.exception = exception; this.headers = headers; } public Exception getException() { return exception; } } }
src/main/java/com/nextcloud/android/sso/api/NetworkRequest.java +4 −2 Original line number Diff line number Diff line Loading @@ -4,14 +4,14 @@ import android.content.Context; import android.os.Looper; import android.util.Log; import androidx.annotation.NonNull; import com.nextcloud.android.sso.aidl.NextcloudRequest; import com.nextcloud.android.sso.helper.ExponentialBackoff; import com.nextcloud.android.sso.model.SingleSignOnAccount; import java.io.InputStream; import androidx.annotation.NonNull; public abstract class NetworkRequest { private static final String TAG = NetworkRequest.class.getCanonicalName(); Loading @@ -38,6 +38,8 @@ public abstract class NetworkRequest { protected abstract InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception; protected abstract Response performNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception; protected void connectApiWithBackoff() { new ExponentialBackoff(1000, 10000, 2, 5, Looper.getMainLooper(), () -> { connect(mAccount.type); Loading
src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java +30 −1 Original line number Diff line number Diff line Loading @@ -119,6 +119,35 @@ public class NextcloudAPI { return networkRequest.performNetworkRequest(request, null); } public Response performRequestV2(final @NonNull Type type, NextcloudRequest request) throws Exception { Log.d(TAG, "performRequest() called with: type = [" + type + "], request = [" + request + "]"); Response result = null; Response response = performNetworkRequestV2(request); Reader targetReader = new InputStreamReader(response.getBody()); if (type != Void.class) { result = gson.fromJson(targetReader, type); if (result != null) { Log.d(TAG, result.toString()); } } return result; } /** * The InputStreams needs to be closed after reading from it * * @param request {@link NextcloudRequest} request to be executed on server via Files app * @return InputStream answer from server as InputStream * @throws Exception or SSOException */ public Response performNetworkRequestV2(NextcloudRequest request) throws Exception { return networkRequest.performNetworkRequestV2(request, null); } /* public static <T> T deserializeObjectAndCloseStream(InputStream is) throws IOException, ClassNotFoundException { Loading
src/main/java/com/nextcloud/android/sso/api/Response.java 0 → 100644 +35 −0 Original line number Diff line number Diff line package com.nextcloud.android.sso.api; import java.io.InputStream; import java.util.ArrayList; import androidx.annotation.Nullable; public class Response { private InputStream body; private ArrayList<AidlNetworkRequest.PlainHeader> headers; public Response(InputStream inputStream, ArrayList<AidlNetworkRequest.PlainHeader> headers) { this.body = inputStream; this.headers = headers; } public ArrayList<AidlNetworkRequest.PlainHeader> getPlainHeaders() { return headers; } public InputStream getBody() { return body; } @Nullable public AidlNetworkRequest.PlainHeader getPlainHeader(String key) { for (AidlNetworkRequest.PlainHeader header: headers) { if (header.getName().equalsIgnoreCase(key)) { return header; } } return null; } }