mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-25 18:48:04 +00:00
Recover from CDN 416 Range error on attachment download.
This commit is contained in:

committed by
Greyson Parrelli

parent
be91f2396c
commit
adea15df10
@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.jobmanager.JobLogger;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
import org.thoughtcrime.securesms.jobmanager.impl.NotInCallConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NotInCallConstraint;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
import org.thoughtcrime.securesms.util.Hex;
|
||||||
@@ -33,13 +34,14 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemo
|
|||||||
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
|
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
import org.whispersystems.signalservice.api.push.exceptions.RangeException;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class AttachmentDownloadJob extends BaseJob {
|
public final class AttachmentDownloadJob extends BaseJob {
|
||||||
|
|
||||||
public static final String KEY = "AttachmentDownloadJob";
|
public static final String KEY = "AttachmentDownloadJob";
|
||||||
|
|
||||||
@@ -107,12 +109,12 @@ public class AttachmentDownloadJob extends BaseJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException {
|
public void onRun() throws Exception {
|
||||||
doWork();
|
doWork();
|
||||||
ApplicationDependencies.getMessageNotifier().updateNotification(context, 0);
|
ApplicationDependencies.getMessageNotifier().updateNotification(context, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doWork() throws IOException {
|
public void doWork() throws IOException, RetryLaterException {
|
||||||
Log.i(TAG, "onRun() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual);
|
Log.i(TAG, "onRun() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual);
|
||||||
|
|
||||||
final AttachmentDatabase database = DatabaseFactory.getAttachmentDatabase(context);
|
final AttachmentDatabase database = DatabaseFactory.getAttachmentDatabase(context);
|
||||||
@@ -151,13 +153,14 @@ public class AttachmentDownloadJob extends BaseJob {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onShouldRetry(@NonNull Exception exception) {
|
protected boolean onShouldRetry(@NonNull Exception exception) {
|
||||||
return (exception instanceof PushNetworkException);
|
return exception instanceof PushNetworkException ||
|
||||||
|
exception instanceof RetryLaterException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retrieveAttachment(long messageId,
|
private void retrieveAttachment(long messageId,
|
||||||
final AttachmentId attachmentId,
|
final AttachmentId attachmentId,
|
||||||
final Attachment attachment)
|
final Attachment attachment)
|
||||||
throws IOException
|
throws IOException, RetryLaterException
|
||||||
{
|
{
|
||||||
|
|
||||||
AttachmentDatabase database = DatabaseFactory.getAttachmentDatabase(context);
|
AttachmentDatabase database = DatabaseFactory.getAttachmentDatabase(context);
|
||||||
@@ -169,6 +172,14 @@ public class AttachmentDownloadJob extends BaseJob {
|
|||||||
InputStream stream = messageReceiver.retrieveAttachment(pointer, attachmentFile, MAX_ATTACHMENT_SIZE, (total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.NETWORK, total, progress)));
|
InputStream stream = messageReceiver.retrieveAttachment(pointer, attachmentFile, MAX_ATTACHMENT_SIZE, (total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.NETWORK, total, progress)));
|
||||||
|
|
||||||
database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream);
|
database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream);
|
||||||
|
} catch (RangeException e) {
|
||||||
|
Log.w(TAG, "Range exception, file size " + attachmentFile.length(), e);
|
||||||
|
if (attachmentFile.delete()) {
|
||||||
|
Log.i(TAG, "Deleted temp download file to recover");
|
||||||
|
throw new RetryLaterException(e);
|
||||||
|
} else {
|
||||||
|
throw new IOException("Failed to delete temp download file following range exception");
|
||||||
|
}
|
||||||
} catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException | MissingConfigurationException e) {
|
} catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException | MissingConfigurationException e) {
|
||||||
Log.w(TAG, "Experienced exception while trying to download an attachment.", e);
|
Log.w(TAG, "Experienced exception while trying to download an attachment.", e);
|
||||||
markFailed(messageId, attachmentId);
|
markFailed(messageId, attachmentId);
|
||||||
|
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2014-2016 Open Whisper Systems
|
||||||
|
* <p>
|
||||||
|
* Licensed according to the LICENSE file in this repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.signalservice.api.push.exceptions;
|
||||||
|
|
||||||
|
public final class RangeException extends NonSuccessfulResponseCodeException {
|
||||||
|
|
||||||
|
public RangeException(long requested) {
|
||||||
|
super("Range request out of bounds " + requested);
|
||||||
|
}
|
||||||
|
}
|
@@ -59,6 +59,7 @@ import org.whispersystems.signalservice.api.push.exceptions.NoContentException;
|
|||||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
|
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
import org.whispersystems.signalservice.api.push.exceptions.RangeException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException;
|
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.RemoteAttestationResponseExpiredException;
|
import org.whispersystems.signalservice.api.push.exceptions.RemoteAttestationResponseExpiredException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.ResumeLocationInvalidException;
|
import org.whispersystems.signalservice.api.push.exceptions.ResumeLocationInvalidException;
|
||||||
@@ -571,7 +572,8 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void retrieveAttachment(int cdnNumber, SignalServiceAttachmentRemoteId cdnPath, File destination, long maxSizeBytes, ProgressListener listener)
|
public void retrieveAttachment(int cdnNumber, SignalServiceAttachmentRemoteId cdnPath, File destination, long maxSizeBytes, ProgressListener listener)
|
||||||
throws NonSuccessfulResponseCodeException, PushNetworkException, MissingConfigurationException {
|
throws IOException, MissingConfigurationException
|
||||||
|
{
|
||||||
final String path;
|
final String path;
|
||||||
if (cdnPath.getV2().isPresent()) {
|
if (cdnPath.getV2().isPresent()) {
|
||||||
path = String.format(Locale.US, ATTACHMENT_ID_DOWNLOAD_PATH, cdnPath.getV2().get());
|
path = String.format(Locale.US, ATTACHMENT_ID_DOWNLOAD_PATH, cdnPath.getV2().get());
|
||||||
@@ -581,12 +583,6 @@ public class PushServiceSocket {
|
|||||||
downloadFromCdn(destination, cdnNumber, path, maxSizeBytes, listener);
|
downloadFromCdn(destination, cdnNumber, path, maxSizeBytes, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void retrieveSticker(File destination, byte[] packId, int stickerId)
|
|
||||||
throws NonSuccessfulResponseCodeException, PushNetworkException, MissingConfigurationException {
|
|
||||||
String hexPackId = Hex.toStringCondensed(packId);
|
|
||||||
downloadFromCdn(destination, 0, String.format(Locale.US, STICKER_PATH, hexPackId, stickerId), 1024 * 1024, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] retrieveSticker(byte[] packId, int stickerId)
|
public byte[] retrieveSticker(byte[] packId, int stickerId)
|
||||||
throws NonSuccessfulResponseCodeException, PushNetworkException {
|
throws NonSuccessfulResponseCodeException, PushNetworkException {
|
||||||
String hexPackId = Hex.toStringCondensed(packId);
|
String hexPackId = Hex.toStringCondensed(packId);
|
||||||
@@ -694,7 +690,8 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void retrieveProfileAvatar(String path, File destination, long maxSizeBytes)
|
public void retrieveProfileAvatar(String path, File destination, long maxSizeBytes)
|
||||||
throws NonSuccessfulResponseCodeException, PushNetworkException {
|
throws IOException
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
downloadFromCdn(destination, 0, path, maxSizeBytes, null);
|
downloadFromCdn(destination, 0, path, maxSizeBytes, null);
|
||||||
} catch (MissingConfigurationException e) {
|
} catch (MissingConfigurationException e) {
|
||||||
@@ -971,11 +968,10 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void downloadFromCdn(File destination, int cdnNumber, String path, long maxSizeBytes, ProgressListener listener)
|
private void downloadFromCdn(File destination, int cdnNumber, String path, long maxSizeBytes, ProgressListener listener)
|
||||||
throws PushNetworkException, NonSuccessfulResponseCodeException, MissingConfigurationException {
|
throws IOException, MissingConfigurationException
|
||||||
|
{
|
||||||
try (FileOutputStream outputStream = new FileOutputStream(destination, true)) {
|
try (FileOutputStream outputStream = new FileOutputStream(destination, true)) {
|
||||||
downloadFromCdn(outputStream, destination.length(), cdnNumber, path, maxSizeBytes, listener);
|
downloadFromCdn(outputStream, destination.length(), cdnNumber, path, maxSizeBytes, listener);
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PushNetworkException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1037,13 +1033,17 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
} else if (response.code() == 416) {
|
||||||
|
throw new RangeException(offset);
|
||||||
}
|
}
|
||||||
|
} catch (NonSuccessfulResponseCodeException | PushNetworkException e) {
|
||||||
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
throw new PushNetworkException(e);
|
||||||
|
} finally {
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
body.close();
|
body.close();
|
||||||
}
|
}
|
||||||
throw new PushNetworkException(e);
|
|
||||||
} finally {
|
|
||||||
synchronized (connections) {
|
synchronized (connections) {
|
||||||
connections.remove(call);
|
connections.remove(call);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user