Skip to content

Commit 229d985

Browse files
Merge pull request #128 from nextcloud/ssoHeaders
SSO: return response headers
2 parents 6f46c64 + 5ec9c69 commit 229d985

File tree

6 files changed

+234
-7
lines changed

6 files changed

+234
-7
lines changed

src/main/aidl/com/nextcloud/android/sso/aidl/IInputStreamService.aidl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
package com.nextcloud.android.sso.aidl;
1919

2020
interface IInputStreamService {
21-
ParcelFileDescriptor performNextcloudRequestAndBodyStream(in ParcelFileDescriptor input, in ParcelFileDescriptor requestBodyParcelFileDescriptor);
21+
ParcelFileDescriptor performNextcloudRequestAndBodyStream(in ParcelFileDescriptor input,
22+
in ParcelFileDescriptor requestBodyParcelFileDescriptor);
2223
ParcelFileDescriptor performNextcloudRequest(in ParcelFileDescriptor input);
24+
25+
ParcelFileDescriptor performNextcloudRequestAndBodyStreamV2(in ParcelFileDescriptor input,
26+
in ParcelFileDescriptor requestBodyParcelFileDescriptor);
27+
ParcelFileDescriptor performNextcloudRequestV2(in ParcelFileDescriptor input);
2328
}

src/main/java/com/nextcloud/android/sso/api/AidlNetworkRequest.java

Lines changed: 150 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
import android.os.RemoteException;
1212
import android.util.Log;
1313

14-
import androidx.annotation.NonNull;
15-
14+
import com.google.gson.Gson;
15+
import com.google.gson.internal.LinkedTreeMap;
1616
import com.nextcloud.android.sso.Constants;
1717
import com.nextcloud.android.sso.aidl.IInputStreamService;
1818
import com.nextcloud.android.sso.aidl.IThreadListener;
@@ -27,8 +27,12 @@
2727
import java.io.InputStream;
2828
import java.io.ObjectInputStream;
2929
import java.io.ObjectOutputStream;
30+
import java.io.Serializable;
31+
import java.util.ArrayList;
3032
import java.util.concurrent.atomic.AtomicBoolean;
3133

34+
import androidx.annotation.NonNull;
35+
3236
import static com.nextcloud.android.sso.exceptions.SSOException.parseNextcloudCustomException;
3337

3438
public class AidlNetworkRequest extends NetworkRequest {
@@ -138,6 +142,31 @@ private void waitForApi() throws NextcloudApiNotRespondingException {
138142
* @return InputStream answer from server as InputStream
139143
* @throws Exception or SSOException
140144
*/
145+
public Response performNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception {
146+
147+
148+
ParcelFileDescriptor output = performAidlNetworkRequestV2(request, requestBodyInputStream);
149+
InputStream os = new ParcelFileDescriptor.AutoCloseInputStream(output);
150+
ExceptionResponse response = deserializeObjectV2(os);
151+
152+
// Handle Remote Exceptions
153+
if (response.getException() != null) {
154+
if (response.getException().getMessage() != null) {
155+
throw parseNextcloudCustomException(response.getException());
156+
}
157+
throw response.getException();
158+
}
159+
return new Response(os, response.headers);
160+
}
161+
162+
/**
163+
* The InputStreams needs to be closed after reading from it
164+
*
165+
* @param request {@link NextcloudRequest} request to be executed on server via Files app
166+
* @param requestBodyInputStream inputstream to be sent to the server
167+
* @return InputStream answer from server as InputStream
168+
* @throws Exception or SSOException
169+
*/
141170
public InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception {
142171
InputStream os = null;
143172
Exception exception;
@@ -168,7 +197,7 @@ public InputStream performNetworkRequest(NextcloudRequest request, InputStream r
168197
* @throws IOException
169198
*/
170199
private ParcelFileDescriptor performAidlNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream)
171-
throws IOException, RemoteException, NextcloudApiNotRespondingException {
200+
throws IOException, RemoteException, NextcloudApiNotRespondingException {
172201

173202
// Check if we are on the main thread
174203
if(Looper.myLooper() == Looper.getMainLooper()) {
@@ -218,10 +247,128 @@ public void onThreadFinished(Thread thread) {
218247
return output;
219248
}
220249

250+
/**
251+
* DO NOT CALL THIS METHOD DIRECTLY - use @link(performNetworkRequestV2) instead
252+
*
253+
* @param request
254+
* @return
255+
* @throws IOException
256+
*/
257+
private ParcelFileDescriptor performAidlNetworkRequestV2(NextcloudRequest request,
258+
InputStream requestBodyInputStream)
259+
throws IOException, RemoteException, NextcloudApiNotRespondingException {
260+
261+
// Check if we are on the main thread
262+
if (Looper.myLooper() == Looper.getMainLooper()) {
263+
throw new NetworkOnMainThreadException();
264+
}
265+
266+
// Wait for api to be initialized
267+
waitForApi();
268+
269+
// Log.d(TAG, request.url);
270+
request.setAccountName(getAccountName());
271+
request.setToken(getAccountToken());
272+
273+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
274+
ObjectOutputStream oos = new ObjectOutputStream(baos);
275+
oos.writeObject(request);
276+
oos.close();
277+
baos.close();
278+
InputStream is = new ByteArrayInputStream(baos.toByteArray());
279+
280+
ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is,
281+
new IThreadListener() {
282+
@Override
283+
public void onThreadFinished(Thread thread) {
284+
Log.d(TAG, "copy data from service finished");
285+
}
286+
});
287+
288+
ParcelFileDescriptor requestBodyParcelFileDescriptor = null;
289+
if (requestBodyInputStream != null) {
290+
requestBodyParcelFileDescriptor = ParcelFileDescriptorUtil.pipeFrom(requestBodyInputStream,
291+
new IThreadListener() {
292+
@Override
293+
public void onThreadFinished(Thread thread) {
294+
Log.d(TAG, "copy data from service finished");
295+
}
296+
});
297+
}
298+
299+
ParcelFileDescriptor output;
300+
if (requestBodyParcelFileDescriptor != null) {
301+
output = mService.performNextcloudRequestAndBodyStreamV2(input, requestBodyParcelFileDescriptor);
302+
} else {
303+
output = mService.performNextcloudRequestV2(input);
304+
}
305+
306+
return output;
307+
}
221308

222309
private static <T> T deserializeObject(InputStream is) throws IOException, ClassNotFoundException {
223310
ObjectInputStream ois = new ObjectInputStream(is);
224311
T result = (T) ois.readObject();
225312
return result;
226313
}
314+
315+
private ExceptionResponse deserializeObjectV2(InputStream is) throws IOException, ClassNotFoundException {
316+
ObjectInputStream ois = new ObjectInputStream(is);
317+
ArrayList<PlainHeader> headerList = new ArrayList<>();
318+
Exception exception = (Exception) ois.readObject();
319+
320+
if (exception == null) {
321+
String headers = (String) ois.readObject();
322+
ArrayList list = new Gson().fromJson(headers, ArrayList.class);
323+
324+
for (Object o : list) {
325+
LinkedTreeMap treeMap = (LinkedTreeMap) o;
326+
headerList.add(new PlainHeader((String) treeMap.get("name"), (String) treeMap.get("value")));
327+
}
328+
}
329+
330+
return new ExceptionResponse(exception, headerList);
331+
}
332+
333+
public class PlainHeader implements Serializable {
334+
private String name;
335+
private String value;
336+
337+
PlainHeader(String name, String value) {
338+
this.name = name;
339+
this.value = value;
340+
}
341+
342+
public String getName() {
343+
return name;
344+
}
345+
346+
public String getValue() {
347+
return value;
348+
}
349+
350+
private void writeObject(ObjectOutputStream oos) throws IOException{
351+
oos.writeObject(name);
352+
oos.writeObject(value);
353+
}
354+
355+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
356+
name = (String) in.readObject();
357+
value = (String) in.readObject();
358+
}
359+
}
360+
361+
private class ExceptionResponse {
362+
private Exception exception;
363+
private ArrayList<PlainHeader> headers;
364+
365+
public ExceptionResponse(Exception exception, ArrayList<PlainHeader> headers) {
366+
this.exception = exception;
367+
this.headers = headers;
368+
}
369+
370+
public Exception getException() {
371+
return exception;
372+
}
373+
}
227374
}

src/main/java/com/nextcloud/android/sso/api/NetworkRequest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
import android.os.Looper;
55
import android.util.Log;
66

7-
import androidx.annotation.NonNull;
8-
97
import com.nextcloud.android.sso.aidl.NextcloudRequest;
108
import com.nextcloud.android.sso.helper.ExponentialBackoff;
119
import com.nextcloud.android.sso.model.SingleSignOnAccount;
1210

1311
import java.io.InputStream;
1412

13+
import androidx.annotation.NonNull;
14+
1515
public abstract class NetworkRequest {
1616

1717
private static final String TAG = NetworkRequest.class.getCanonicalName();
@@ -38,6 +38,8 @@ protected void connect(String type) {
3838

3939
protected abstract InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception;
4040

41+
protected abstract Response performNetworkRequestV2(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception;
42+
4143
protected void connectApiWithBackoff() {
4244
new ExponentialBackoff(1000, 10000, 2, 5, Looper.getMainLooper(), () -> {
4345
connect(mAccount.type);

src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,39 @@ public <T> T performRequest(final @NonNull Type type, NextcloudRequest request)
115115
* @return InputStream answer from server as InputStream
116116
* @throws Exception or SSOException
117117
*/
118-
public InputStream performNetworkRequest(NextcloudRequest request) throws Exception {
118+
public InputStream performNetworkRequest(NextcloudRequest request) throws Exception {
119119
return networkRequest.performNetworkRequest(request, null);
120120
}
121121

122+
public Response performRequestV2(final @NonNull Type type, NextcloudRequest request) throws Exception {
123+
Log.d(TAG, "performRequest() called with: type = [" + type + "], request = [" + request + "]");
124+
125+
Response result = null;
126+
Response response = performNetworkRequestV2(request);
127+
Reader targetReader = new InputStreamReader(response.getBody());
128+
129+
if (type != Void.class) {
130+
result = gson.fromJson(targetReader, type);
131+
if (result != null) {
132+
Log.d(TAG, result.toString());
133+
}
134+
135+
}
136+
return result;
137+
}
138+
139+
140+
/**
141+
* The InputStreams needs to be closed after reading from it
142+
*
143+
* @param request {@link NextcloudRequest} request to be executed on server via Files app
144+
* @return InputStream answer from server as InputStream
145+
* @throws Exception or SSOException
146+
*/
147+
public Response performNetworkRequestV2(NextcloudRequest request) throws Exception {
148+
return networkRequest.performNetworkRequestV2(request, null);
149+
}
150+
122151

123152
/*
124153
public static <T> T deserializeObjectAndCloseStream(InputStream is) throws IOException, ClassNotFoundException {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.nextcloud.android.sso.api;
2+
3+
import java.io.InputStream;
4+
import java.util.ArrayList;
5+
6+
import androidx.annotation.Nullable;
7+
8+
public class Response {
9+
private InputStream body;
10+
private ArrayList<AidlNetworkRequest.PlainHeader> headers;
11+
12+
public Response(InputStream inputStream, ArrayList<AidlNetworkRequest.PlainHeader> headers) {
13+
this.body = inputStream;
14+
this.headers = headers;
15+
}
16+
17+
public ArrayList<AidlNetworkRequest.PlainHeader> getPlainHeaders() {
18+
return headers;
19+
}
20+
21+
public InputStream getBody() {
22+
return body;
23+
}
24+
25+
@Nullable
26+
public AidlNetworkRequest.PlainHeader getPlainHeader(String key) {
27+
for (AidlNetworkRequest.PlainHeader header: headers) {
28+
if (header.getName().equalsIgnoreCase(key)) {
29+
return header;
30+
}
31+
}
32+
33+
return null;
34+
}
35+
}

src/main/java/com/nextcloud/android/sso/helper/Okhttp3Helper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,13 @@ public static ResponseBody getResponseBodyFromRequest(NextcloudAPI nextcloudAPI,
4444
return ResponseBody.create(null, "");
4545
}
4646

47+
public static ResponseBody getResponseBodyFromRequestV2(NextcloudAPI nextcloudAPI, NextcloudRequest request) {
48+
try {
49+
InputStream os = nextcloudAPI.performNetworkRequestV2(request).getBody();
50+
return ResponseBody.create(null, 0, new BufferedSourceSSO(os));
51+
} catch (Exception e) {
52+
Log.e(TAG, "[getResponseBodyFromRequest] encountered a problem", e);
53+
}
54+
return ResponseBody.create(null, "");
55+
}
4756
}

0 commit comments

Comments
 (0)