Skip to content

Commit d402073

Browse files
mikehardytimrae
authored andcommitted
Switch to okhttp for http connections, use TLS1.2 on API<=21 (#5658)
1 parent 1c8eee7 commit d402073

File tree

12 files changed

+351
-308
lines changed

12 files changed

+351
-308
lines changed

AnkiDroid/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ android {
5959
buildConfigField "String", "ACRA_URL", '"https://ankidroid.org/acra/report"'
6060
}
6161
}
62-
useLibrary 'org.apache.http.legacy'
6362

6463
testOptions {
6564
animationsDisabled true

AnkiDroid/src/main/AndroidManifest.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,6 @@
356356
<uses-library
357357
android:name="com.sec.android.app.multiwindow"
358358
android:required="false" />
359-
<uses-library
360-
android:name="org.apache.http.legacy"
361-
android:required="false" />
362359

363360
<meta-data
364361
android:name="com.sec.android.support.multiwindow"

AnkiDroid/src/main/java/com/ichi2/async/Connection.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
import java.io.IOException;
4747

48+
import okhttp3.Response;
4849
import timber.log.Timber;
4950

5051
public class Connection extends BaseAsyncTask<Connection.Payload, Object, Connection.Payload> {
@@ -199,12 +200,11 @@ private Payload doOneInBackground(Payload data) {
199200
}
200201

201202

202-
@SuppressWarnings("deprecation") // tracking HTTP transport change in github already
203203
private Payload doInBackgroundLogin(Payload data) {
204204
String username = (String) data.data[0];
205205
String password = (String) data.data[1];
206206
HttpSyncer server = new RemoteServer(this, null);
207-
org.apache.http.HttpResponse ret;
207+
Response ret;
208208
try {
209209
ret = server.hostKey(username, password);
210210
} catch (UnknownHttpResponseException e) {
@@ -223,16 +223,16 @@ private Payload doInBackgroundLogin(Payload data) {
223223
String hostkey = null;
224224
boolean valid = false;
225225
if (ret != null) {
226-
data.returnType = ret.getStatusLine().getStatusCode();
227-
Timber.d("doInBackgroundLogin - response from server: %d, (%s)", data.returnType, ret.getStatusLine().getReasonPhrase());
226+
data.returnType = ret.code();
227+
Timber.d("doInBackgroundLogin - response from server: %d, (%s)", data.returnType, ret.message());
228228
if (data.returnType == 200) {
229229
try {
230-
JSONObject jo = (new JSONObject(server.stream2String(ret.getEntity().getContent())));
230+
JSONObject jo = (new JSONObject(ret.body().string()));
231231
hostkey = jo.getString("key");
232232
valid = (hostkey != null) && (hostkey.length() > 0);
233233
} catch (JSONException e) {
234234
valid = false;
235-
} catch (IllegalStateException | IOException e) {
235+
} catch (IllegalStateException | IOException | NullPointerException e) {
236236
throw new RuntimeException(e);
237237
}
238238
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/****************************************************************************************
2+
* Copyright (c) 2019 Mike Hardy <[email protected]> *
3+
* *
4+
* This program is free software; you can redistribute it and/or modify it under *
5+
* the terms of the GNU General Public License as published by the Free Software *
6+
* Foundation; either version 3 of the License, or (at your option) any later *
7+
* version. *
8+
* *
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
10+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
11+
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
12+
* *
13+
* You should have received a copy of the GNU General Public License along with *
14+
* this program. If not, see <http://www.gnu.org/licenses/>. *
15+
****************************************************************************************/
16+
17+
package com.ichi2.libanki.sync;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
22+
import okhttp3.MediaType;
23+
import okhttp3.RequestBody;
24+
import okhttp3.internal.Util;
25+
import okio.BufferedSink;
26+
import okio.Okio;
27+
import okio.Source;
28+
29+
30+
// Note that in current versions of OkHTTP this is unnecessary as they support
31+
// Decorators / hooks more easily with the builder API, allowing upload transfer tracking
32+
// without a separate object. I believe we will have to move to API21+ for that to be possible
33+
public class CountingFileRequestBody extends RequestBody {
34+
35+
private static final int SEGMENT_SIZE = 2048; // okio.Segment.SIZE
36+
37+
private final File file;
38+
private final ProgressListener listener;
39+
private final String contentType;
40+
41+
public CountingFileRequestBody(File file, String contentType, ProgressListener listener) {
42+
this.file = file;
43+
this.contentType = contentType;
44+
this.listener = listener;
45+
}
46+
47+
@Override
48+
public long contentLength() {
49+
return file.length();
50+
}
51+
52+
@Override
53+
public MediaType contentType() {
54+
return MediaType.parse(contentType);
55+
}
56+
57+
@Override
58+
public void writeTo(BufferedSink sink) throws IOException {
59+
Source source = null;
60+
try {
61+
source = Okio.source(file);
62+
long read;
63+
64+
while ((read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
65+
sink.flush();
66+
this.listener.transferred(read);
67+
}
68+
} finally {
69+
Util.closeQuietly(source);
70+
}
71+
}
72+
73+
public interface ProgressListener {
74+
void transferred(long num);
75+
}
76+
}

AnkiDroid/src/main/java/com/ichi2/libanki/sync/FullSyncer.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import java.util.HashMap;
4040
import java.util.Locale;
4141

42+
import okhttp3.Response;
43+
import okhttp3.ResponseBody;
4244
import timber.log.Timber;
4345

4446
@SuppressWarnings({"PMD.AvoidThrowingRawExceptionTypes","PMD.NPathComplexity"})
@@ -73,19 +75,21 @@ public String syncURL() {
7375

7476

7577
@Override
76-
@SuppressWarnings("deprecation") // tracking HTTP transport change in github already
7778
public Object[] download() throws UnknownHttpResponseException {
7879
InputStream cont;
80+
ResponseBody body = null;
7981
try {
80-
org.apache.http.HttpResponse ret = super.req("download");
81-
if (ret == null) {
82+
Response ret = super.req("download");
83+
if (ret == null || ret.body() == null) {
8284
return null;
8385
}
84-
cont = ret.getEntity().getContent();
85-
} catch (IllegalStateException e1) {
86+
body = ret.body();
87+
cont = body.byteStream();
88+
} catch (IllegalArgumentException e1) {
89+
if (body != null) {
90+
body.close();
91+
}
8692
throw new RuntimeException(e1);
87-
} catch (IOException e1) {
88-
return null;
8993
}
9094
String path;
9195
if (mCol != null) {
@@ -111,6 +115,8 @@ public Object[] download() throws UnknownHttpResponseException {
111115
} catch (IOException e) {
112116
Timber.e(e, "Full sync failed to download collection.");
113117
return new Object[] { "sdAccessError" };
118+
} finally {
119+
body.close();
114120
}
115121

116122
// check the received file is ok
@@ -141,7 +147,6 @@ public Object[] download() throws UnknownHttpResponseException {
141147

142148

143149
@Override
144-
@SuppressWarnings("deprecation") // tracking HTTP transport change in github already
145150
public Object[] upload() throws UnknownHttpResponseException {
146151
// make sure it's ok before we try to upload
147152
mCon.publishProgress(R.string.sync_check_upload_file);
@@ -154,19 +159,19 @@ public Object[] upload() throws UnknownHttpResponseException {
154159
// apply some adjustments, then upload
155160
mCol.beforeUpload();
156161
String filePath = mCol.getPath();
157-
org.apache.http.HttpResponse ret;
162+
Response ret;
158163
mCon.publishProgress(R.string.sync_uploading_message);
159164
try {
160165
ret = super.req("upload", new FileInputStream(filePath));
161-
if (ret == null) {
166+
if (ret == null || ret.body() == null) {
162167
return null;
163168
}
164-
int status = ret.getStatusLine().getStatusCode();
169+
int status = ret.code();
165170
if (status != 200) {
166171
// error occurred
167-
return new Object[] { "error", status, ret.getStatusLine().getReasonPhrase() };
172+
return new Object[] { "error", status, ret.message() };
168173
} else {
169-
return new Object[] { super.stream2String(ret.getEntity().getContent()) };
174+
return new Object[] { ret.body().string() };
170175
}
171176
} catch (IllegalStateException | IOException e) {
172177
throw new RuntimeException(e);

0 commit comments

Comments
 (0)