Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import org.wordpress.android.fluxc.store.AccountStore
import org.wordpress.android.fluxc.utils.AppLogWrapper
import org.wordpress.android.modules.IO_THREAD
import org.wordpress.android.util.AppLog
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.net.HttpURLConnection
import java.net.URL
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Named
import kotlin.collections.forEach

class TempAttachmentsUtil @Inject constructor(
@Named(IO_THREAD) private val ioDispatcher: CoroutineDispatcher,
@Named("regular") private val okHttpClient: OkHttpClient,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Can we use a constant here? There are 4 instances of "regular" in the PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've looked at the same thing while reviewing the changes and found that this is extensively used across the code base. So, introducing a constant would need to be done in a separate PR - or we'd either introduce inconsistency or change too many irrelevant files.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it!

private val appLogWrapper: AppLogWrapper,
private val application: Application,
private val accountStore: AccountStore
Expand Down Expand Up @@ -97,44 +99,46 @@ class TempAttachmentsUtil @Inject constructor(
@Suppress("TooGenericExceptionCaught")
suspend fun createVideoTempFile(videoUrl: String): File? = withContext(ioDispatcher) {
var tempFile: File? = null
var connection: HttpURLConnection? = null

try {
tempFile = File.createTempFile("video_", ".mp4", application.cacheDir)
connection = (URL(videoUrl).openConnection() as HttpURLConnection).apply {
requestMethod = "GET"
setRequestProperty("Authorization", "Bearer ${accountStore.accessToken}")
instanceFollowRedirects = true
connectTimeout = CONNECTION_TIMEOUT_MS
readTimeout = READ_TIMEOUT_MS
}

connection.connect()

val responseCode = connection.responseCode
AppLog.d(AppLog.T.SUPPORT, "Download response code: $responseCode")

if (responseCode == HttpURLConnection.HTTP_OK) {
connection.inputStream.use { input ->
tempFile.outputStream().use { output ->
input.copyTo(output)
val request = Request.Builder()
.url(videoUrl)
.addHeader("Authorization", "Bearer ${accountStore.accessToken}")
.build()

val client = okHttpClient.newBuilder()
.connectTimeout(CONNECTION_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS)
.readTimeout(READ_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS)
.build()

client.newCall(request).execute().use { response ->
val responseCode = response.code
AppLog.d(AppLog.T.SUPPORT, "Download response code: $responseCode")

if (response.isSuccessful) {
response.body?.byteStream()?.use { input ->
tempFile.outputStream().use { output ->
input.copyTo(output)
}
}
}

AppLog.d(AppLog.T.SUPPORT, "Video downloaded: ${tempFile.absolutePath}")
tempFile
} else {
val deleted = tempFile?.delete()
AppLog.e(AppLog.T.SUPPORT, "Failed to download video. Deleted: ${deleted} - " +
"Response code: $responseCode")
null
AppLog.d(AppLog.T.SUPPORT, "Video downloaded: ${tempFile.absolutePath}")
tempFile
} else {
val deleted = tempFile?.delete()
AppLog.e(
AppLog.T.SUPPORT,
"Failed to download video. Deleted: $deleted - Response code: $responseCode"
)
null
}
}
} catch (e: Exception) {
val deleted = tempFile?.delete()
AppLog.e(AppLog.T.SUPPORT, "Error downloading video: ${e.message} Deleted: ${deleted}")
AppLog.e(AppLog.T.SUPPORT, "Error downloading video: ${e.message} Deleted: $deleted")
null
} finally {
connection?.disconnect()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import org.wordpress.android.modules.UI_THREAD
import org.wordpress.android.ui.utils.AuthenticationUtils
import org.wordpress.android.util.AppLog.T
import org.wordpress.android.util.MediaUtilsWrapper
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException
import java.net.URL
import javax.inject.Inject
Expand All @@ -23,6 +25,7 @@ class VideoLoader
@Inject constructor(
@param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
@param:Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher,
@param:Named("regular") private val okHttpClient: OkHttpClient,
private val authenticationUtils: AuthenticationUtils,
private val appLogWrapper: AppLogWrapper,
private val mediaUtilsWrapper: MediaUtilsWrapper,
Expand Down Expand Up @@ -67,16 +70,17 @@ class VideoLoader
}

private fun getSizeFromURL(url: URL): Int {
val urlConnection = url.openConnection()
for ((key, value) in authenticationUtils.getAuthHeaders(url.toString()).entries) {
urlConnection.addRequestProperty(key, value)
val requestBuilder = Request.Builder()
.url(url)
.head()

authenticationUtils.getAuthHeaders(url.toString()).forEach { (key, value) ->
requestBuilder.addHeader(key, value)
}

var length = urlConnection.contentLength
if (length <= MIN_SIZE) {
length = urlConnection.getHeaderFieldInt("Content-Length", MIN_SIZE)
return okHttpClient.newCall(requestBuilder.build()).execute().use { response ->
response.header("Content-Length")?.toIntOrNull() ?: MIN_SIZE
}
return length
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@
import org.wordpress.android.util.helpers.WebChromeClientWithVideoPoster;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Named;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/*
* WebView descendant used by ReaderPostDetailFragment - handles
Expand Down Expand Up @@ -81,6 +86,7 @@

@Inject UserAgent mUserAgent;
@Inject AccountStore mAccountStore;
@Inject @Named("regular") OkHttpClient mOkHttpClient;

public ReaderWebView(Context context) {
super(context);
Expand All @@ -106,7 +112,7 @@

mReaderChromeClient = new ReaderWebChromeClient(this);
this.setWebChromeClient(mReaderChromeClient);
this.setWebViewClient(new ReaderWebViewClient(this, mUserAgent));
this.setWebViewClient(new ReaderWebViewClient(this, mUserAgent, mOkHttpClient));
this.getSettings().setUserAgentString(mUserAgent.getWebViewUserAgent());

// Enable third-party cookies since they are disabled by default;
Expand Down Expand Up @@ -260,18 +266,20 @@
}
}
return super.onTouchEvent(event);
}

Check notice

Code scanning / Android Lint

Nullable/NonNull annotation missing on constructor parameter Note

Missing null annotation

Check notice

Code scanning / Android Lint

Nullable/NonNull annotation missing on constructor parameter Note

Missing null annotation

private static class ReaderWebViewClient extends WebViewClient {
private final ReaderWebView mReaderWebView;
private final UserAgent mUserAgent;
private final OkHttpClient mOkHttpClient;

ReaderWebViewClient(ReaderWebView readerWebView, UserAgent userAgent) {
ReaderWebViewClient(ReaderWebView readerWebView, UserAgent userAgent, OkHttpClient okHttpClient) {
if (readerWebView == null) {
throw new IllegalArgumentException("ReaderWebViewClient requires readerWebView");
}
mReaderWebView = readerWebView;
mUserAgent = userAgent;
mOkHttpClient = okHttpClient;
}


Expand Down Expand Up @@ -310,15 +318,26 @@
if (imageUrl != null && WPUrlUtils.safeToAddWordPressComAuthToken(imageUrl)
&& !TextUtils.isEmpty(mToken)) {
try {
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
conn.setRequestProperty("Authorization", "Bearer " + mToken);
conn.setReadTimeout(TIMEOUT_MS);
conn.setConnectTimeout(TIMEOUT_MS);
conn.setRequestProperty("User-Agent", mUserAgent.getWebViewUserAgent());
conn.setRequestProperty("Connection", "Keep-Alive");
return new WebResourceResponse(conn.getContentType(),
conn.getContentEncoding(),
conn.getInputStream());
Request request = new Request.Builder()
.url(imageUrl)
.addHeader("Authorization", "Bearer " + mToken)
.addHeader("User-Agent", mUserAgent.getWebViewUserAgent())
.addHeader("Connection", "Keep-Alive")
.build();

OkHttpClient client = mOkHttpClient.newBuilder()
.connectTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
.build();

Response okResponse = client.newCall(request).execute();
if (okResponse.body() != null) {
return new WebResourceResponse(
okResponse.header("Content-Type"),
okResponse.header("Content-Encoding"),
okResponse.body().byteStream()
);
}
} catch (IOException e) {
AppLog.e(AppLog.T.READER, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@
import org.wordpress.android.fluxc.network.MemorizingTrustManager;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Named;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

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

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

public WPWebViewClient(SiteModel site, String token, List<String> urls,
ErrorManagedWebViewClientListener listener) {
Expand Down Expand Up @@ -72,16 +78,24 @@ public WebResourceResponse shouldInterceptRequest(WebView view, String stringUrl
&& !TextUtils.isEmpty(mToken)) {
try {
// Force use of HTTPS for the resource, otherwise the request will fail for private sites
HttpURLConnection urlConnection = (HttpURLConnection) imageUrl.openConnection();
urlConnection.setRequestProperty("Authorization", "Bearer " + mToken);
urlConnection.setReadTimeout(TIMEOUT_MS);
urlConnection.setConnectTimeout(TIMEOUT_MS);
WebResourceResponse response = new WebResourceResponse(urlConnection.getContentType(),
urlConnection.getContentEncoding(),
urlConnection.getInputStream());
return response;
} catch (ClassCastException e) {
AppLog.e(AppLog.T.POSTS, "Invalid connection type - URL: " + stringUrl);
Request request = new Request.Builder()
.url(imageUrl)
.addHeader("Authorization", "Bearer " + mToken)
.build();

OkHttpClient client = mOkHttpClient.newBuilder()
.connectTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)
.build();

Response okResponse = client.newCall(request).execute();
if (okResponse.body() != null) {
return new WebResourceResponse(
okResponse.header("Content-Type"),
okResponse.header("Content-Encoding"),
okResponse.body().byteStream()
);
}
} catch (MalformedURLException e) {
AppLog.e(AppLog.T.POSTS, "Malformed URL: " + stringUrl);
} catch (IOException e) {
Expand Down
Loading