Skip to content

Commit 8ffd5e0

Browse files
authored
Migrate HttpURLConnection usages to OkHttp (#22375)
* Migrate VideoLoader from HttpURLConnection to OkHttp Replace direct HttpURLConnection usage with the shared OkHttpClient for better connection pooling and consistency with the rest of the codebase. Changes: - Inject `@Named("regular") OkHttpClient` via Dagger - Use HEAD request instead of GET for efficiency (only need Content-Length) - Simplify content length retrieval using OkHttp's response API * Migrate TempAttachmentsUtil from HttpURLConnection to OkHttp Replace direct HttpURLConnection usage with the shared OkHttpClient for video downloads in support ticket attachments. Changes: - Inject `@Named("regular") OkHttpClient` via Dagger - Use `okHttpClient.newBuilder()` to configure custom timeouts - Stream response body to temp file using OkHttp's byteStream API - Simplify cleanup by relying on OkHttp's response.use {} auto-close * Migrate WPWebViewClient from HttpURLConnection to OkHttp Replace direct HttpURLConnection usage with the shared OkHttpClient for intercepting private site image requests in WebViews. Changes: - Inject `@Named("regular") OkHttpClient` via Dagger field injection - Use synchronous `execute()` as required by `shouldInterceptRequest` - Configure timeouts via `newBuilder()` to preserve existing behavior - Pass response body stream directly to WebResourceResponse * Migrate ReaderWebView from HttpURLConnection to OkHttp Replace direct HttpURLConnection usage with the shared OkHttpClient for intercepting private post image requests in Reader WebViews. Changes: - Inject `@Named("regular") OkHttpClient` in ReaderWebView - Pass OkHttpClient to inner ReaderWebViewClient class - Use synchronous `execute()` as required by `shouldInterceptRequest` - Preserve User-Agent and Connection headers from original implementation
1 parent 192a695 commit 8ffd5e0

File tree

4 files changed

+101
-60
lines changed

4 files changed

+101
-60
lines changed

WordPress/src/main/java/org/wordpress/android/support/he/util/TempAttachmentsUtil.kt

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ import org.wordpress.android.fluxc.store.AccountStore
88
import org.wordpress.android.fluxc.utils.AppLogWrapper
99
import org.wordpress.android.modules.IO_THREAD
1010
import org.wordpress.android.util.AppLog
11+
import okhttp3.OkHttpClient
12+
import okhttp3.Request
1113
import java.io.File
12-
import java.net.HttpURLConnection
13-
import java.net.URL
14+
import java.util.concurrent.TimeUnit
1415
import javax.inject.Inject
1516
import javax.inject.Named
1617
import kotlin.collections.forEach
1718

1819
class TempAttachmentsUtil @Inject constructor(
1920
@Named(IO_THREAD) private val ioDispatcher: CoroutineDispatcher,
21+
@Named("regular") private val okHttpClient: OkHttpClient,
2022
private val appLogWrapper: AppLogWrapper,
2123
private val application: Application,
2224
private val accountStore: AccountStore
@@ -97,44 +99,46 @@ class TempAttachmentsUtil @Inject constructor(
9799
@Suppress("TooGenericExceptionCaught")
98100
suspend fun createVideoTempFile(videoUrl: String): File? = withContext(ioDispatcher) {
99101
var tempFile: File? = null
100-
var connection: HttpURLConnection? = null
101102

102103
try {
103104
tempFile = File.createTempFile("video_", ".mp4", application.cacheDir)
104-
connection = (URL(videoUrl).openConnection() as HttpURLConnection).apply {
105-
requestMethod = "GET"
106-
setRequestProperty("Authorization", "Bearer ${accountStore.accessToken}")
107-
instanceFollowRedirects = true
108-
connectTimeout = CONNECTION_TIMEOUT_MS
109-
readTimeout = READ_TIMEOUT_MS
110-
}
111-
112-
connection.connect()
113-
114-
val responseCode = connection.responseCode
115-
AppLog.d(AppLog.T.SUPPORT, "Download response code: $responseCode")
116105

117-
if (responseCode == HttpURLConnection.HTTP_OK) {
118-
connection.inputStream.use { input ->
119-
tempFile.outputStream().use { output ->
120-
input.copyTo(output)
106+
val request = Request.Builder()
107+
.url(videoUrl)
108+
.addHeader("Authorization", "Bearer ${accountStore.accessToken}")
109+
.build()
110+
111+
val client = okHttpClient.newBuilder()
112+
.connectTimeout(CONNECTION_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS)
113+
.readTimeout(READ_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS)
114+
.build()
115+
116+
client.newCall(request).execute().use { response ->
117+
val responseCode = response.code
118+
AppLog.d(AppLog.T.SUPPORT, "Download response code: $responseCode")
119+
120+
if (response.isSuccessful) {
121+
response.body?.byteStream()?.use { input ->
122+
tempFile.outputStream().use { output ->
123+
input.copyTo(output)
124+
}
121125
}
122-
}
123126

124-
AppLog.d(AppLog.T.SUPPORT, "Video downloaded: ${tempFile.absolutePath}")
125-
tempFile
126-
} else {
127-
val deleted = tempFile?.delete()
128-
AppLog.e(AppLog.T.SUPPORT, "Failed to download video. Deleted: ${deleted} - " +
129-
"Response code: $responseCode")
130-
null
127+
AppLog.d(AppLog.T.SUPPORT, "Video downloaded: ${tempFile.absolutePath}")
128+
tempFile
129+
} else {
130+
val deleted = tempFile?.delete()
131+
AppLog.e(
132+
AppLog.T.SUPPORT,
133+
"Failed to download video. Deleted: $deleted - Response code: $responseCode"
134+
)
135+
null
136+
}
131137
}
132138
} catch (e: Exception) {
133139
val deleted = tempFile?.delete()
134-
AppLog.e(AppLog.T.SUPPORT, "Error downloading video: ${e.message} Deleted: ${deleted}")
140+
AppLog.e(AppLog.T.SUPPORT, "Error downloading video: ${e.message} Deleted: $deleted")
135141
null
136-
} finally {
137-
connection?.disconnect()
138142
}
139143
}
140144
}

WordPress/src/main/java/org/wordpress/android/ui/media/VideoLoader.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import org.wordpress.android.modules.UI_THREAD
1414
import org.wordpress.android.ui.utils.AuthenticationUtils
1515
import org.wordpress.android.util.AppLog.T
1616
import org.wordpress.android.util.MediaUtilsWrapper
17+
import okhttp3.OkHttpClient
18+
import okhttp3.Request
1719
import java.io.IOException
1820
import java.net.URL
1921
import javax.inject.Inject
@@ -23,6 +25,7 @@ class VideoLoader
2325
@Inject constructor(
2426
@param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
2527
@param:Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher,
28+
@param:Named("regular") private val okHttpClient: OkHttpClient,
2629
private val authenticationUtils: AuthenticationUtils,
2730
private val appLogWrapper: AppLogWrapper,
2831
private val mediaUtilsWrapper: MediaUtilsWrapper,
@@ -67,16 +70,17 @@ class VideoLoader
6770
}
6871

6972
private fun getSizeFromURL(url: URL): Int {
70-
val urlConnection = url.openConnection()
71-
for ((key, value) in authenticationUtils.getAuthHeaders(url.toString()).entries) {
72-
urlConnection.addRequestProperty(key, value)
73+
val requestBuilder = Request.Builder()
74+
.url(url)
75+
.head()
76+
77+
authenticationUtils.getAuthHeaders(url.toString()).forEach { (key, value) ->
78+
requestBuilder.addHeader(key, value)
7379
}
7480

75-
var length = urlConnection.contentLength
76-
if (length <= MIN_SIZE) {
77-
length = urlConnection.getHeaderFieldInt("Content-Length", MIN_SIZE)
81+
return okHttpClient.newCall(requestBuilder.build()).execute().use { response ->
82+
response.header("Content-Length")?.toIntOrNull() ?: MIN_SIZE
7883
}
79-
return length
8084
}
8185

8286
companion object {

WordPress/src/main/java/org/wordpress/android/ui/reader/views/ReaderWebView.java

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,16 @@
2727
import org.wordpress.android.util.helpers.WebChromeClientWithVideoPoster;
2828

2929
import java.io.IOException;
30-
import java.net.HttpURLConnection;
3130
import java.net.MalformedURLException;
3231
import java.net.URL;
32+
import java.util.concurrent.TimeUnit;
3333

3434
import javax.inject.Inject;
35+
import javax.inject.Named;
36+
37+
import okhttp3.OkHttpClient;
38+
import okhttp3.Request;
39+
import okhttp3.Response;
3540

3641
/*
3742
* WebView descendant used by ReaderPostDetailFragment - handles
@@ -81,6 +86,7 @@ public interface ReaderWebViewPageFinishedListener {
8186

8287
@Inject UserAgent mUserAgent;
8388
@Inject AccountStore mAccountStore;
89+
@Inject @Named("regular") OkHttpClient mOkHttpClient;
8490

8591
public ReaderWebView(Context context) {
8692
super(context);
@@ -106,7 +112,7 @@ private void init(Context context) {
106112

107113
mReaderChromeClient = new ReaderWebChromeClient(this);
108114
this.setWebChromeClient(mReaderChromeClient);
109-
this.setWebViewClient(new ReaderWebViewClient(this, mUserAgent));
115+
this.setWebViewClient(new ReaderWebViewClient(this, mUserAgent, mOkHttpClient));
110116
this.getSettings().setUserAgentString(mUserAgent.getWebViewUserAgent());
111117

112118
// Enable third-party cookies since they are disabled by default;
@@ -265,13 +271,15 @@ public boolean onTouchEvent(MotionEvent event) {
265271
private static class ReaderWebViewClient extends WebViewClient {
266272
private final ReaderWebView mReaderWebView;
267273
private final UserAgent mUserAgent;
274+
private final OkHttpClient mOkHttpClient;
268275

269-
ReaderWebViewClient(ReaderWebView readerWebView, UserAgent userAgent) {
276+
ReaderWebViewClient(ReaderWebView readerWebView, UserAgent userAgent, OkHttpClient okHttpClient) {
270277
if (readerWebView == null) {
271278
throw new IllegalArgumentException("ReaderWebViewClient requires readerWebView");
272279
}
273280
mReaderWebView = readerWebView;
274281
mUserAgent = userAgent;
282+
mOkHttpClient = okHttpClient;
275283
}
276284

277285

@@ -310,15 +318,26 @@ public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
310318
if (imageUrl != null && WPUrlUtils.safeToAddWordPressComAuthToken(imageUrl)
311319
&& !TextUtils.isEmpty(mToken)) {
312320
try {
313-
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
314-
conn.setRequestProperty("Authorization", "Bearer " + mToken);
315-
conn.setReadTimeout(TIMEOUT_MS);
316-
conn.setConnectTimeout(TIMEOUT_MS);
317-
conn.setRequestProperty("User-Agent", mUserAgent.getWebViewUserAgent());
318-
conn.setRequestProperty("Connection", "Keep-Alive");
319-
return new WebResourceResponse(conn.getContentType(),
320-
conn.getContentEncoding(),
321-
conn.getInputStream());
321+
Request request = new Request.Builder()
322+
.url(imageUrl)
323+
.addHeader("Authorization", "Bearer " + mToken)
324+
.addHeader("User-Agent", mUserAgent.getWebViewUserAgent())
325+
.addHeader("Connection", "Keep-Alive")
326+
.build();
327+
328+
OkHttpClient client = mOkHttpClient.newBuilder()
329+
.connectTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
330+
.readTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
331+
.build();
332+
333+
Response okResponse = client.newCall(request).execute();
334+
if (okResponse.body() != null) {
335+
return new WebResourceResponse(
336+
okResponse.header("Content-Type"),
337+
okResponse.header("Content-Encoding"),
338+
okResponse.body().byteStream()
339+
);
340+
}
322341
} catch (IOException e) {
323342
AppLog.e(AppLog.T.READER, e);
324343
}

WordPress/src/main/java/org/wordpress/android/util/WPWebViewClient.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@
1212
import org.wordpress.android.fluxc.network.MemorizingTrustManager;
1313

1414
import java.io.IOException;
15-
import java.net.HttpURLConnection;
1615
import java.net.MalformedURLException;
1716
import java.net.URL;
1817
import java.security.cert.X509Certificate;
1918
import java.util.List;
19+
import java.util.concurrent.TimeUnit;
2020

2121
import javax.inject.Inject;
22+
import javax.inject.Named;
23+
24+
import okhttp3.OkHttpClient;
25+
import okhttp3.Request;
26+
import okhttp3.Response;
2227

2328
import static org.wordpress.android.util.SelfSignedSSLUtils.sslCertificateToX509;
2429

@@ -35,6 +40,7 @@ public class WPWebViewClient extends URLFilteredWebViewClient {
3540
private final SiteModel mSite;
3641
private String mToken;
3742
@Inject protected MemorizingTrustManager mMemorizingTrustManager;
43+
@Inject @Named("regular") protected OkHttpClient mOkHttpClient;
3844

3945
public WPWebViewClient(SiteModel site, String token, List<String> urls,
4046
ErrorManagedWebViewClientListener listener) {
@@ -72,16 +78,24 @@ public WebResourceResponse shouldInterceptRequest(WebView view, String stringUrl
7278
&& !TextUtils.isEmpty(mToken)) {
7379
try {
7480
// Force use of HTTPS for the resource, otherwise the request will fail for private sites
75-
HttpURLConnection urlConnection = (HttpURLConnection) imageUrl.openConnection();
76-
urlConnection.setRequestProperty("Authorization", "Bearer " + mToken);
77-
urlConnection.setReadTimeout(TIMEOUT_MS);
78-
urlConnection.setConnectTimeout(TIMEOUT_MS);
79-
WebResourceResponse response = new WebResourceResponse(urlConnection.getContentType(),
80-
urlConnection.getContentEncoding(),
81-
urlConnection.getInputStream());
82-
return response;
83-
} catch (ClassCastException e) {
84-
AppLog.e(AppLog.T.POSTS, "Invalid connection type - URL: " + stringUrl);
81+
Request request = new Request.Builder()
82+
.url(imageUrl)
83+
.addHeader("Authorization", "Bearer " + mToken)
84+
.build();
85+
86+
OkHttpClient client = mOkHttpClient.newBuilder()
87+
.connectTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
88+
.readTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
89+
.build();
90+
91+
Response okResponse = client.newCall(request).execute();
92+
if (okResponse.body() != null) {
93+
return new WebResourceResponse(
94+
okResponse.header("Content-Type"),
95+
okResponse.header("Content-Encoding"),
96+
okResponse.body().byteStream()
97+
);
98+
}
8599
} catch (MalformedURLException e) {
86100
AppLog.e(AppLog.T.POSTS, "Malformed URL: " + stringUrl);
87101
} catch (IOException e) {

0 commit comments

Comments
 (0)