11/***************************************************************************************
22 * Copyright (c) 2012 Norbert Nagold <norbert.nagold@gmail.com> *
33 * Copyright (c) 2012 Kostas Spyropoulos <inigo.aldana@gmail.com> *
4- * Copyright (c) 2014 Timothy Rae <perceptualchaos2@gmail.com>
4+ * Copyright (c) 2014 Timothy Rae <perceptualchaos2@gmail.com> *
5+ * Copyright (c) 2019 Mike Hardy <github@mikehardy.net> *
56 * *
67 * This program is free software; you can redistribute it and/or modify it under *
78 * the terms of the GNU General Public License as published by the Free Software *
3031import com .ichi2 .libanki .Utils ;
3132import com .ichi2 .utils .VersionUtils ;
3233
33- import org .apache .commons . httpclient . contrib . ssl . EasySSLSocketFactory ;
34+ import org .apache .http . entity . AbstractHttpEntity ;
3435import org .json .JSONException ;
3536import org .json .JSONObject ;
3637
5253import java .util .Locale ;
5354import java .util .Map ;
5455import java .util .Random ;
56+ import java .util .concurrent .TimeUnit ;
5557import java .util .zip .GZIPOutputStream ;
5658
5759import javax .net .ssl .SSLException ;
5860
61+ import okhttp3 .MediaType ;
62+ import okhttp3 .OkHttpClient ;
63+ import okhttp3 .Request ;
64+ import okhttp3 .RequestBody ;
65+ import okhttp3 .Response ;
5966import timber .log .Timber ;
6067
6168/**
6572 * - 502: ankiweb down
6673 * - 503/504: server too busy
6774 */
68- @ SuppressWarnings ({"PMD.AvoidThrowingRawExceptionTypes" ,"PMD.NPathComplexity" ,
69- "deprecation" }) // tracking HTTP transport change in github already
75+ @ SuppressWarnings ({"PMD.AvoidThrowingRawExceptionTypes" ,"PMD.NPathComplexity" })
7076public class HttpSyncer {
7177
7278 private static final String BOUNDARY = "Anki-sync-boundary" ;
79+ private static final MediaType ANKI_POST_TYPE = MediaType .get ("multipart/form-data; boundary=" + BOUNDARY );
80+
7381 public static final String ANKIWEB_STATUS_OK = "OK" ;
7482
7583 public volatile long bytesSent = 0 ;
@@ -95,40 +103,40 @@ public HttpSyncer(String hkey, Connection con) {
95103 }
96104
97105
98- public void assertOk (org . apache . http . HttpResponse resp ) throws UnknownHttpResponseException {
106+ public void assertOk (Response resp ) throws UnknownHttpResponseException {
99107 // Throw RuntimeException if HTTP error
100108 if (resp == null ) {
101109 throw new UnknownHttpResponseException ("Null HttpResponse" , -2 );
102110 }
103- int resultCode = resp .getStatusLine (). getStatusCode ();
111+ int resultCode = resp .code ();
104112 if (!(resultCode == 200 || resultCode == 403 )) {
105- String reason = resp .getStatusLine (). getReasonPhrase ();
113+ String reason = resp .message ();
106114 throw new UnknownHttpResponseException (reason , resultCode );
107115 }
108116 }
109117
110118
111- public org . apache . http . HttpResponse req (String method ) throws UnknownHttpResponseException {
119+ public Response req (String method ) throws UnknownHttpResponseException {
112120 return req (method , null );
113121 }
114122
115123
116- public org . apache . http . HttpResponse req (String method , InputStream fobj ) throws UnknownHttpResponseException {
124+ public Response req (String method , InputStream fobj ) throws UnknownHttpResponseException {
117125 return req (method , fobj , 6 );
118126 }
119127
120128
121- public org . apache . http . HttpResponse req (String method , int comp , InputStream fobj ) throws UnknownHttpResponseException {
129+ public Response req (String method , int comp , InputStream fobj ) throws UnknownHttpResponseException {
122130 return req (method , fobj , comp );
123131 }
124132
125133
126- public org . apache . http . HttpResponse req (String method , InputStream fobj , int comp ) throws UnknownHttpResponseException {
134+ public Response req (String method , InputStream fobj , int comp ) throws UnknownHttpResponseException {
127135 return req (method , fobj , comp , null );
128136 }
129137
130138
131- private org . apache . http . HttpResponse req (String method , InputStream fobj , int comp , JSONObject registerData ) throws UnknownHttpResponseException {
139+ private Response req (String method , InputStream fobj , int comp , JSONObject registerData ) throws UnknownHttpResponseException {
132140 File tmpFileBuffer = null ;
133141 try {
134142 String bdry = "--" + BOUNDARY ;
@@ -185,31 +193,33 @@ private org.apache.http.HttpResponse req(String method, InputStream fobj, int co
185193 } else {
186194 url = syncURL () + method ;
187195 }
188- org .apache .http .client .methods .HttpPost httpPost = new org .apache .http .client .methods .HttpPost (url );
189- org .apache .http .HttpEntity entity = new ProgressByteEntity (tmpFileBuffer );
190196
191- // body
192- httpPost .setEntity (entity );
193- httpPost .setHeader ("Content-type" , "multipart/form-data; boundary=" + BOUNDARY );
197+ // FIXME need to implement a Request subclass that emits progress as the stream is drained e.g. https://stackoverflow.com/a/26376724/9910298
198+ Request .Builder requestBuilder = new Request .Builder ();
199+ requestBuilder .url (url );
200+ requestBuilder .post (RequestBody .create (ANKI_POST_TYPE , tmpFileBuffer ));
201+ Request httpPost = requestBuilder .build ();
194202
195203 // HttpParams
196- org .apache .http .params .HttpParams params = new org .apache .http .params .BasicHttpParams ();
197- params .setParameter (org .apache .http .conn .params .ConnManagerPNames .MAX_TOTAL_CONNECTIONS , 30 );
198- params .setParameter (org .apache .http .conn .params .ConnManagerPNames .MAX_CONNECTIONS_PER_ROUTE , new org .apache .http .conn .params .ConnPerRouteBean (30 ));
199- params .setParameter (org .apache .http .params .CoreProtocolPNames .USE_EXPECT_CONTINUE , false );
200- params .setParameter (org .apache .http .params .CoreProtocolPNames .USER_AGENT , "AnkiDroid-" + VersionUtils .getPkgVersionName ());
201- org .apache .http .params .HttpProtocolParams .setVersion (params , org .apache .http .HttpVersion .HTTP_1_1 );
202- org .apache .http .params .HttpConnectionParams .setSoTimeout (params , Connection .CONN_TIMEOUT );
203-
204- // Registry
205- org .apache .http .conn .scheme .SchemeRegistry registry = new org .apache .http .conn .scheme .SchemeRegistry ();
206- registry .register (new org .apache .http .conn .scheme .Scheme ("http" , org .apache .http .conn .scheme .PlainSocketFactory .getSocketFactory (), 80 ));
207- registry .register (new org .apache .http .conn .scheme .Scheme ("https" , new EasySSLSocketFactory (), 443 ));
208- org .apache .http .impl .conn .tsccm .ThreadSafeClientConnManager cm = new org .apache .http .impl .conn .tsccm .ThreadSafeClientConnManager (params , registry );
209-
204+ // org.apache.http.params.HttpParams params = new org.apache.http.params.BasicHttpParams();
205+ // params.setParameter(org.apache.http.conn.params.ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
206+ // params.setParameter(org.apache.http.conn.params.ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new org.apache.http.conn.params.ConnPerRouteBean(30));
207+ // params.setParameter(org.apache.http.params.CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
208+ // params.setParameter(org.apache.http.params.CoreProtocolPNames.USER_AGENT, "AnkiDroid-" + VersionUtils.getPkgVersionName());
209+ // org.apache.http.params.HttpProtocolParams.setVersion(params, org.apache.http.HttpVersion.HTTP_1_1);
210210 try {
211- org .apache .http .client .HttpClient httpClient = new org .apache .http .impl .client .DefaultHttpClient (cm , params );
212- org .apache .http .HttpResponse httpResponse = httpClient .execute (httpPost );
211+ OkHttpClient .Builder clientBuilder = new OkHttpClient .Builder ();
212+
213+ clientBuilder .followRedirects (true )
214+ .followSslRedirects (true )
215+ .retryOnConnectionFailure (true )
216+ .cache (null )
217+
218+ .connectTimeout (Connection .CONN_TIMEOUT , TimeUnit .SECONDS )
219+ .writeTimeout (Connection .CONN_TIMEOUT , TimeUnit .SECONDS )
220+ .readTimeout (Connection .CONN_TIMEOUT , TimeUnit .SECONDS );
221+ OkHttpClient httpClient = new OkHttpClient ();
222+ Response httpResponse = httpClient .newCall (httpPost ).execute ();
213223 // we assume badAuthRaises flag from Anki Desktop always False
214224 // so just throw new RuntimeException if response code not 200 or 403
215225 assertOk (httpResponse );
@@ -295,7 +305,7 @@ private void publishProgress() {
295305 }
296306
297307
298- public org . apache . http . HttpResponse hostKey (String arg1 , String arg2 ) throws UnknownHttpResponseException {
308+ public Response hostKey (String arg1 , String arg2 ) throws UnknownHttpResponseException {
299309 return null ;
300310 }
301311
@@ -324,7 +334,7 @@ public void abort() throws UnknownHttpResponseException {
324334 }
325335
326336
327- public org . apache . http . HttpResponse meta () throws UnknownHttpResponseException {
337+ public Response meta () throws UnknownHttpResponseException {
328338 return null ;
329339 }
330340
@@ -348,7 +358,7 @@ public void applyChunk(JSONObject sech) throws UnknownHttpResponseException {
348358 // do nothing
349359 }
350360
351- public class ProgressByteEntity extends org . apache . http . entity . AbstractHttpEntity {
361+ public class ProgressByteEntity extends AbstractHttpEntity {
352362
353363 private InputStream mInputStream ;
354364 private long mLength ;
0 commit comments