Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 229d985a authored by Tobias Kaminsky's avatar Tobias Kaminsky Committed by GitHub
Browse files

Merge pull request #128 from nextcloud/ssoHeaders

SSO: return response headers
parents 6f46c646 5ec9c69f
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -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);
}
+150 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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 {
@@ -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
     *
@@ -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;
        }
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -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();
@@ -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);
+30 −1
Original line number Diff line number Diff line
@@ -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 {
+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