1919
2020package com .here .olp .network ;
2121
22- import android .annotation .SuppressLint ;
2322import android .os .AsyncTask ;
2423import android .os .OperationCanceledException ;
2524import android .util .Log ;
2827import java .io .FileNotFoundException ;
2928import java .io .IOException ;
3029import java .io .InputStream ;
30+ import java .lang .ref .WeakReference ;
3131import java .net .HttpURLConnection ;
3232import java .net .InetSocketAddress ;
3333import java .net .MalformedURLException ;
3434import java .net .ProtocolException ;
3535import java .net .Proxy ;
36+ import java .net .SocketTimeoutException ;
3637import java .net .URL ;
3738import java .net .URLConnection ;
3839import java .net .UnknownHostException ;
39- import java .net .SocketTimeoutException ;
40- import java .util .concurrent .atomic .AtomicBoolean ;
41- import java .util .concurrent .ExecutorService ;
42- import java .util .concurrent .Executors ;
4340import java .util .List ;
4441import java .util .Map ;
42+ import java .util .concurrent .ExecutorService ;
43+ import java .util .concurrent .Executors ;
44+ import java .util .concurrent .atomic .AtomicBoolean ;
4545
4646import javax .net .ssl .SSLException ;
4747
@@ -94,17 +94,17 @@ public static HttpVerb toHttpVerb(int verb) {
9494 /** Class to hold the request's data, which will be used by HttpUrlConnection object. */
9595 public final class Request {
9696 public Request (
97- String url ,
98- HttpVerb verb ,
99- long requestId ,
100- int connectionTimeout ,
101- int requestTimeout ,
102- String [] headers ,
103- byte [] postData ,
104- String proxyServer ,
105- int proxyPort ,
106- int proxyType ,
107- int maxRetries ) {
97+ String url ,
98+ HttpVerb verb ,
99+ long requestId ,
100+ int connectionTimeout ,
101+ int requestTimeout ,
102+ String [] headers ,
103+ byte [] postData ,
104+ String proxyServer ,
105+ int proxyPort ,
106+ int proxyType ,
107+ int maxRetries ) {
108108 this .url = url ;
109109 this .verb = verb ;
110110 this .requestId = requestId ;
@@ -129,18 +129,10 @@ public Request(
129129 case 4 :
130130 case 5 :
131131 this .proxyType = Proxy .Type .SOCKS ;
132- Log .w (
133- LOGTAG ,
134- "HttpClient::Request(): Unsupported proxy version ("
135- + proxyType
136- + "). Falling back to SOCKS4(4)" );
132+ Log .w (LOGTAG , "HttpClient::Request(): Unsupported proxy version (" + proxyType + "). Falling back to SOCKS4(4)" );
137133 break ;
138134 default :
139- Log .w (
140- LOGTAG ,
141- "HttpClient::Request(): Unsupported proxy version ("
142- + proxyType
143- + "). Falling back to HTTP(0)" );
135+ Log .w (LOGTAG , "HttpClient::Request(): Unsupported proxy version (" + proxyType + "). Falling back to HTTP(0)" );
144136 this .proxyType = Proxy .Type .HTTP ;
145137 break ;
146138 }
@@ -215,14 +207,18 @@ public final int maxRetries() {
215207 /**
216208 * Task class sends the request HttpUrlConnection and responsible for handling response as well.
217209 */
218- @ SuppressLint ( "StaticFieldLeak" )
219- private class HttpTask extends AsyncTask < Request , Void , Void > {
220- private AtomicBoolean cancelled = new AtomicBoolean (false );
210+ private static class HttpTask extends AsyncTask < Request , Void , Void > {
211+ private final WeakReference < HttpClient > weakReference ;
212+ private final AtomicBoolean cancelled = new AtomicBoolean (false );
221213
222214 public synchronized void cancelTask () {
223215 this .cancelled .set (true );
224216 }
225217
218+ private HttpTask (HttpClient client ) {
219+ weakReference = new WeakReference <>(client );
220+ }
221+
226222 @ Override
227223 protected Void doInBackground (Request ... requests ) {
228224 for (Request request : requests ) {
@@ -234,9 +230,14 @@ protected Void doInBackground(Request... requests) {
234230 try {
235231 int retryCount = 0 ;
236232 boolean isDone = false ;
237- URL url = new URL (request .url ());
233+ final URL url = new URL (request .url ());
238234
239235 do {
236+ final HttpClient httpClient = weakReference .get ();
237+ if (httpClient == null ) {
238+ return null ;
239+ }
240+
240241 // TODO: replace with more elegant and controlled approach
241242 if (retryCount > 0 ) {
242243 Thread .sleep (100 );
@@ -250,10 +251,10 @@ protected Void doInBackground(Request... requests) {
250251 conn = url .openConnection (Proxy .NO_PROXY );
251252 } else {
252253 conn =
253- url .openConnection (
254- new Proxy (
255- request .proxyType (),
256- new InetSocketAddress (request .proxyServer (), request .proxyPort ())));
254+ url .openConnection (
255+ new Proxy (
256+ request .proxyType (),
257+ new InetSocketAddress (request .proxyServer (), request .proxyPort ())));
257258 }
258259 } else {
259260 conn = url .openConnection ();
@@ -349,15 +350,15 @@ protected Void doInBackground(Request... requests) {
349350 error = httpConn .getResponseMessage ();
350351
351352 if ((status > 0 )
352- && ((status < HttpURLConnection .HTTP_OK )
353+ && ((status < HttpURLConnection .HTTP_OK )
353354 || (status >= HttpURLConnection .HTTP_SERVER_ERROR ))) {
354355 if (retryCount ++ < request .maxRetries ()) {
355356 continue ;
356357 }
357358 }
358359 } catch (SocketTimeoutException | UnknownHostException e ) {
359360 if (retryCount ++ < request .maxRetries ()) {
360- resetRequest (request .requestId ());
361+ httpClient . resetRequest (request .requestId ());
361362 continue ;
362363 } else {
363364 throw e ;
@@ -396,8 +397,8 @@ protected Void doInBackground(Request... requests) {
396397
397398 int contentSize = conn .getContentLength ();
398399 if (contentSize > 0 ){
399- downloadContentSize += contentSize ;
400- downloadContentSizePresent = true ;
400+ downloadContentSize += contentSize ;
401+ downloadContentSizePresent = true ;
401402 }
402403
403404 // Get all the headers of the response
@@ -414,8 +415,8 @@ protected Void doInBackground(Request... requests) {
414415
415416 checkCancelled ();
416417
417- headersCallback (request .requestId (), headersArray );
418- dateAndOffsetCallback (request .requestId (), 0l , offset );
418+ httpClient . headersCallback (request .requestId (), headersArray );
419+ httpClient . dateAndOffsetCallback (request .requestId (), 0l , offset );
419420
420421 // Do the input phase
421422 InputStream in = null ;
@@ -435,9 +436,9 @@ protected Void doInBackground(Request... requests) {
435436
436437 while ((len = in .read (buffer )) >= 0 ) {
437438 checkCancelled ();
438- dataCallback (request .requestId (), buffer , len );
439+ httpClient . dataCallback (request .requestId (), buffer , len );
439440 if (!downloadContentSizePresent ){
440- downloadContentSize += len ;
441+ downloadContentSize += len ;
441442 }
442443 }
443444 }
@@ -449,12 +450,12 @@ protected Void doInBackground(Request... requests) {
449450 }
450451 } catch (ProtocolException e ) {
451452 if (status != HttpURLConnection .HTTP_NOT_MODIFIED
452- && status != HttpURLConnection .HTTP_NO_CONTENT ) {
453+ && status != HttpURLConnection .HTTP_NO_CONTENT ) {
453454 throw e ;
454455 }
455456 } catch (SocketTimeoutException e ) {
456457 if (retryCount ++ < request .maxRetries ()) {
457- resetRequest (request .requestId ());
458+ httpClient . resetRequest (request .requestId ());
458459 continue ;
459460 } else {
460461 throw e ;
@@ -466,24 +467,22 @@ protected Void doInBackground(Request... requests) {
466467 // The request is completed, not cancelled or retried
467468 // Notifies the native (C++) side that request was completed
468469 isDone = true ;
469- completeRequest (request .requestId (), status , uploadedContentSize , downloadContentSize , error , contentType );
470+ httpClient . completeRequest (request .requestId (), status , uploadedContentSize , downloadContentSize , error , contentType );
470471 } while (!isDone );
471472 } catch (SSLException e ) {
472- completeRequest (request .requestId (), AUTHORIZATION_ERROR , uploadedContentSize , downloadContentSize , "SSL connection failed." , " " );
473+ completeErrorRequest (request .requestId (), AUTHORIZATION_ERROR , uploadedContentSize , downloadContentSize , "SSL connection failed." );
473474 } catch (MalformedURLException e ) {
474- completeRequest (
475- request .requestId (), INVALID_URL_ERROR , uploadedContentSize , downloadContentSize , "The provided URL is not valid." , "" );
475+ completeErrorRequest (request .requestId (), INVALID_URL_ERROR , uploadedContentSize , downloadContentSize , "The provided URL is not valid." );
476476 } catch (OperationCanceledException e ) {
477- completeRequest (request .requestId (), CANCELLED_ERROR , uploadedContentSize , downloadContentSize , "Cancelled" , " " );
477+ completeErrorRequest (request .requestId (), CANCELLED_ERROR , uploadedContentSize , downloadContentSize , "Cancelled" );
478478 } catch (SocketTimeoutException e ) {
479- completeRequest (request .requestId (), TIMEOUT_ERROR , uploadedContentSize , downloadContentSize , "Timed out" , "" );
480- } catch (java .net .UnknownHostException e ) {
481- completeRequest (
482- request .requestId (), OFFLINE_ERROR , uploadedContentSize , downloadContentSize , "The device has no internet connectivity" , "" );
479+ completeErrorRequest (request .requestId (), TIMEOUT_ERROR , uploadedContentSize , downloadContentSize , "Timed out" );
480+ } catch (UnknownHostException e ) {
481+ completeErrorRequest (request .requestId (), OFFLINE_ERROR , uploadedContentSize , downloadContentSize , "The device has no internet connectivity" );
483482 } catch (Exception e ) {
484483 Log .e (LOGTAG , "HttpClient::HttpTask::run exception: " + e );
485484 e .printStackTrace ();
486- completeRequest (request .requestId (), IO_ERROR , uploadedContentSize , downloadContentSize , e .toString (), "" );
485+ completeErrorRequest (request .requestId (), IO_ERROR , uploadedContentSize , downloadContentSize , e .toString ());
487486 } finally {
488487 uploadedContentSize = 0 ;
489488 downloadContentSize = 0 ;
@@ -494,6 +493,13 @@ protected Void doInBackground(Request... requests) {
494493 return null ;
495494 }
496495
496+ private void completeErrorRequest (long requestId , int status , int uploadedBytes , int downloadedBytes , String error ) {
497+ final HttpClient httpClient = weakReference .get ();
498+ if (httpClient != null ) {
499+ httpClient .completeRequest (requestId , status , uploadedBytes , downloadedBytes , error , "" );
500+ }
501+ }
502+
497503 private final void checkCancelled () {
498504 if (this .cancelled .get ()) {
499505 throw new OperationCanceledException ();
@@ -571,7 +577,7 @@ private final int calculateHeadersSize(Map<String, List<String>> headers) throws
571577 }
572578 for (String value : values ) {
573579 if (value != null ) {
574- size += value .length ();
580+ size += value .length ();
575581 }
576582 }
577583 }
@@ -597,31 +603,31 @@ public void shutdown() {
597603 }
598604
599605 public HttpTask send (
600- String url ,
601- int httpMethod ,
602- long requestId ,
603- int connTimeout ,
604- int reqTimeout ,
605- String [] headers ,
606- byte [] postData ,
607- String proxyServer ,
608- int proxyPort ,
609- int proxyType ,
610- int maxRetries ) {
611- Request request =
612- new Request (
613- url ,
614- HttpClient .toHttpVerb (httpMethod ),
615- requestId ,
616- connTimeout ,
617- reqTimeout ,
618- headers ,
619- postData ,
620- proxyServer ,
621- proxyPort ,
622- proxyType ,
623- maxRetries );
624- HttpTask task = new HttpTask ();
606+ String url ,
607+ int httpMethod ,
608+ long requestId ,
609+ int connTimeout ,
610+ int reqTimeout ,
611+ String [] headers ,
612+ byte [] postData ,
613+ String proxyServer ,
614+ int proxyPort ,
615+ int proxyType ,
616+ int maxRetries ) {
617+ final Request request =
618+ new Request (
619+ url ,
620+ HttpClient .toHttpVerb (httpMethod ),
621+ requestId ,
622+ connTimeout ,
623+ reqTimeout ,
624+ headers ,
625+ postData ,
626+ proxyServer ,
627+ proxyPort ,
628+ proxyType ,
629+ maxRetries );
630+ final HttpTask task = new HttpTask (this );
625631 task .executeOnExecutor (executor , request );
626632 return task ;
627633 }
@@ -630,7 +636,7 @@ public HttpTask send(
630636 // Synchronization is required in order to provide thread-safe access to `nativePtr`
631637 // Callback for completed request
632638 private synchronized native void completeRequest (
633- long requestId , int status , int uploadedBytes , int downloadedBytes , String error , String contentType );
639+ long requestId , int status , int uploadedBytes , int downloadedBytes , String error , String contentType );
634640 // Callback for data received
635641 private synchronized native void dataCallback (long requestId , byte [] data , int len );
636642 // Callback set date and offset
@@ -639,4 +645,4 @@ private synchronized native void completeRequest(
639645 private synchronized native void headersCallback (long requestId , String [] headers );
640646 // Reset request for retry
641647 private synchronized native void resetRequest (long requestId );
642- }
648+ }
0 commit comments