Commit dd7b379d by christosts Committed by Oliver Woodman

DataSource.open() throws if already opened.

Update DataSource implementations to throw an error if open() is called
when the DataSource is already open.

PiperOrigin-RevId: 348609860
parent 02265430
Showing with 90 additions and 18 deletions
......@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.ext.media2;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Context;
import android.net.Uri;
import android.os.Looper;
......@@ -143,6 +145,7 @@ import org.junit.rules.ExternalResource;
private final DataSource wrappedDataSource;
private final DataSourceInstrumentation instrumentation;
private boolean opened;
public InstrumentedDataSource(
DataSource wrappedDataSource, DataSourceInstrumentation instrumentation) {
......@@ -157,8 +160,11 @@ import org.junit.rules.ExternalResource;
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
instrumentation.onPreOpen(dataSpec);
return wrappedDataSource.open(dataSpec);
long length = wrappedDataSource.open(dataSpec);
opened = true;
return length;
}
@Nullable
......@@ -180,6 +186,7 @@ import org.junit.rules.ExternalResource;
@Override
public void close() throws IOException {
wrappedDataSource.close();
opened = false;
}
}
}
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.ext.okhttp;
import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -277,6 +278,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
@Override
public long open(DataSpec dataSpec) throws HttpDataSourceException {
checkState(!opened);
this.dataSpec = dataSpec;
this.bytesRead = 0;
this.bytesSkipped = 0;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.ext.rtmp;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.net.Uri;
......@@ -37,6 +38,7 @@ public final class RtmpDataSource extends BaseDataSource {
@Nullable private RtmpClient rtmpClient;
@Nullable private Uri uri;
private boolean opened;
public RtmpDataSource() {
super(/* isNetwork= */ true);
......@@ -44,12 +46,14 @@ public final class RtmpDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws RtmpIOException {
checkState(!opened);
transferInitializing(dataSpec);
rtmpClient = new RtmpClient();
rtmpClient.open(dataSpec.uri.toString(), false);
this.uri = dataSpec.uri;
transferStarted(dataSpec);
opened = true;
return C.LENGTH_UNSET;
}
......@@ -73,6 +77,7 @@ public final class RtmpDataSource extends BaseDataSource {
rtmpClient.close();
rtmpClient = null;
}
opened = false;
}
@Override
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -57,6 +58,7 @@ public final class AssetDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws AssetDataSourceException {
checkState(!opened);
try {
uri = dataSpec.uri;
String path = Assertions.checkNotNull(uri.getPath());
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.min;
import android.net.Uri;
......@@ -45,6 +46,7 @@ public final class ByteArrayDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
uri = dataSpec.uri;
transferInitializing(dataSpec);
readPosition = (int) dataSpec.position;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -62,6 +63,8 @@ public final class ContentDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws ContentDataSourceException {
checkState(!opened);
try {
Uri uri = dataSpec.uri;
this.uri = uri;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -44,6 +45,7 @@ public final class DataSchemeDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(this.dataSpec == null);
transferInitializing(dataSpec);
this.dataSpec = dataSpec;
readPosition = (int) dataSpec.position;
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.max;
import static java.lang.Math.min;
......@@ -342,6 +343,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
*/
@Override
public long open(DataSpec dataSpec) throws HttpDataSourceException {
checkState(!opened);
this.dataSpec = dataSpec;
this.bytesRead = 0;
this.bytesSkipped = 0;
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -80,6 +81,7 @@ public final class FileDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws FileDataSourceException {
checkState(!opened);
try {
Uri uri = dataSpec.uri;
this.uri = uri;
......
......@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions;
......@@ -40,6 +42,7 @@ public final class PriorityDataSource implements DataSource {
private final DataSource upstream;
private final PriorityTaskManager priorityTaskManager;
private final int priority;
private boolean opened;
/**
* @param upstream The upstream {@link DataSource}.
......@@ -61,8 +64,11 @@ public final class PriorityDataSource implements DataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
priorityTaskManager.proceedOrThrow(priority);
return upstream.open(dataSpec);
long length = upstream.open(dataSpec);
opened = true;
return length;
}
@Override
......@@ -85,6 +91,7 @@ public final class PriorityDataSource implements DataSource {
@Override
public void close() throws IOException {
upstream.close();
opened = false;
}
}
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -98,6 +99,7 @@ public final class RawResourceDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws RawResourceDataSourceException {
checkState(!opened);
Uri uri = dataSpec.uri;
this.uri = uri;
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri;
import androidx.annotation.Nullable;
......@@ -103,6 +104,7 @@ public final class ResolvingDataSource implements DataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!upstreamOpened);
DataSpec resolvedDataSpec = resolver.resolveDataSpec(dataSpec);
upstreamOpened = true;
return upstreamDataSource.open(resolvedDataSpec);
......
......@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
......@@ -35,6 +37,7 @@ public final class StatsDataSource implements DataSource {
private long bytesRead;
private Uri lastOpenedUri;
private Map<String, List<String>> lastResponseHeaders;
private boolean opened;
/**
* Creates the stats data source.
......@@ -78,12 +81,14 @@ public final class StatsDataSource implements DataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
// Reassign defaults in case dataSource.open throws an exception.
lastOpenedUri = dataSpec.uri;
lastResponseHeaders = Collections.emptyMap();
long availableBytes = dataSource.open(dataSpec);
lastOpenedUri = Assertions.checkNotNull(getUri());
lastResponseHeaders = getResponseHeaders();
opened = true;
return availableBytes;
}
......@@ -110,5 +115,6 @@ public final class StatsDataSource implements DataSource {
@Override
public void close() throws IOException {
dataSource.close();
opened = false;
}
}
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.min;
import android.net.Uri;
......@@ -89,6 +90,8 @@ public final class UdpDataSource extends BaseDataSource {
@Override
public long open(DataSpec dataSpec) throws UdpDataSourceException {
checkState(!opened);
uri = dataSpec.uri;
String host = uri.getHost();
int port = uri.getPort();
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream.cache;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
......@@ -33,7 +34,6 @@ import com.google.android.exoplayer2.upstream.PriorityDataSource;
import com.google.android.exoplayer2.upstream.TeeDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.upstream.cache.Cache.CacheException;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.io.IOException;
import java.io.InterruptedIOException;
......@@ -397,6 +397,7 @@ public final class CacheDataSource implements DataSource {
private boolean currentRequestIgnoresCache;
private long totalCachedBytesRead;
private long checkCachePosition;
private boolean opened;
/**
* Constructs an instance with default {@link DataSource} and {@link DataSink} instances for
......@@ -552,6 +553,7 @@ public final class CacheDataSource implements DataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
try {
String key = cacheKeyFactory.buildCacheKey(dataSpec);
DataSpec requestDataSpec = dataSpec.buildUpon().setKey(key).build();
......@@ -577,6 +579,7 @@ public final class CacheDataSource implements DataSource {
}
}
openNextSource(requestDataSpec, false);
opened = true;
return bytesRemaining;
} catch (Throwable e) {
handleBeforeThrow(e);
......@@ -649,6 +652,7 @@ public final class CacheDataSource implements DataSource {
notifyBytesRead();
try {
closeCurrentSource();
opened = false;
} catch (Throwable e) {
handleBeforeThrow(e);
throw e;
......@@ -739,7 +743,7 @@ public final class CacheDataSource implements DataSource {
? readPosition + MIN_READ_BEFORE_CHECKING_CACHE
: Long.MAX_VALUE;
if (checkCache) {
Assertions.checkState(isBypassingCache());
checkState(isBypassingCache());
if (nextDataSource == upstreamDataSource) {
// Continue reading from upstream.
return;
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream.crypto;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.net.Uri;
......@@ -36,6 +37,7 @@ public final class AesCipherDataSource implements DataSource {
private final DataSource upstream;
private final byte[] secretKey;
private boolean opened;
@Nullable private AesFlushingCipher cipher;
......@@ -52,11 +54,13 @@ public final class AesCipherDataSource implements DataSource {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
long dataLength = upstream.open(dataSpec);
long nonce = CryptoUtil.getFNV64Hash(dataSpec.key);
cipher =
new AesFlushingCipher(
Cipher.DECRYPT_MODE, secretKey, nonce, dataSpec.uriPositionOffset + dataSpec.position);
opened = true;
return dataLength;
}
......@@ -88,5 +92,6 @@ public final class AesCipherDataSource implements DataSource {
public void close() throws IOException {
cipher = null;
upstream.close();
opened = false;
}
}
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
......@@ -89,14 +90,18 @@ public class BaseDataSourceTest {
private static final class TestSource extends BaseDataSource {
private boolean opened;
public TestSource(boolean isNetwork) {
super(isNetwork);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
transferInitializing(dataSpec);
transferStarted(dataSpec);
opened = true;
return C.LENGTH_UNSET;
}
......@@ -115,6 +120,7 @@ public class BaseDataSourceTest {
@Override
public void close() throws IOException {
transferEnded();
opened = false;
}
}
......
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.C.RESULT_END_OF_INPUT;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import android.net.Uri;
......@@ -130,19 +131,20 @@ public final class DataSchemeDataSourceTest {
}
@Test
public void malformedData() {
try {
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,,This%20is%20Content"));
fail();
} catch (IOException e) {
// Expected.
}
try {
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,IncorrectPadding=="));
fail();
} catch (IOException e) {
// Expected.
}
public void malformedData_throwsIOException() {
assertThrows(
IOException.class,
() ->
schemeDataDataSource.open(
buildDataSpec("data:text/plain;base64,,This%20is%20Content")));
}
@Test
public void malformedData_incorrectPadding_throwsIOException() {
assertThrows(
IOException.class,
() ->
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,IncorrectPadding==")));
}
@Test
......
......@@ -284,6 +284,7 @@ public final class CacheDataSourceTest {
cacheDataSource.open(
buildDataSpec(TEST_DATA.length - 2, C.LENGTH_UNSET, defaultCacheKey)))
.isEqualTo(2);
cacheDataSource.close();
// An unbounded request with offset for not cached content.
dataSpec =
......
......@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.source.hls;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
......@@ -50,6 +52,7 @@ import javax.crypto.spec.SecretKeySpec;
private final DataSource upstream;
private final byte[] encryptionKey;
private final byte[] encryptionIv;
private boolean opened;
@Nullable private CipherInputStream cipherInputStream;
......@@ -72,6 +75,7 @@ import javax.crypto.spec.SecretKeySpec;
@Override
public final long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
Cipher cipher;
try {
cipher = getCipherInstance();
......@@ -91,7 +95,7 @@ import javax.crypto.spec.SecretKeySpec;
DataSourceInputStream inputStream = new DataSourceInputStream(upstream, dataSpec);
cipherInputStream = new CipherInputStream(inputStream, cipher);
inputStream.open();
opened = true;
return C.LENGTH_UNSET;
}
......@@ -121,6 +125,7 @@ import javax.crypto.spec.SecretKeySpec;
if (cipherInputStream != null) {
cipherInputStream = null;
upstream.close();
opened = false;
}
}
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.hls;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
......@@ -104,6 +105,7 @@ public class Aes128DataSourceTest {
@Override
public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
opened = true;
return C.LENGTH_UNSET;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment