Skip to content

Commit 15c5388

Browse files
committed
tests for url redirections
1 parent 8263814 commit 15c5388

8 files changed

Lines changed: 152 additions & 61 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ repositories {
1212
maven { url 'https://dl.bintray.com/alexeydanilov/maven' }
1313
}
1414
dependencies {
15-
compile 'com.danikula:videocache:2.0.9'
15+
compile 'com.danikula:videocache:2.1.0'
1616
}
1717
```
1818

library/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ publish {
2626
userOrg = 'alexeydanilov'
2727
groupId = 'com.danikula'
2828
artifactId = 'videocache'
29-
publishVersion = '2.0.9'
29+
publishVersion = '2.1.0'
3030
description = 'Cache support for android VideoView'
3131
website = 'https://github.com/danikula/AndroidVideoCache'
3232
}

library/src/main/java/com/danikula/videocache/HttpUrlSource.java

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.text.TextUtils;
44
import android.util.Log;
5+
56
import java.io.BufferedInputStream;
67
import java.io.IOException;
78
import java.io.InputStream;
@@ -11,8 +12,11 @@
1112

1213
import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE;
1314
import static com.danikula.videocache.ProxyCacheUtils.LOG_TAG;
15+
import static java.net.HttpURLConnection.HTTP_MOVED_PERM;
16+
import static java.net.HttpURLConnection.HTTP_MOVED_TEMP;
1417
import static java.net.HttpURLConnection.HTTP_OK;
1518
import static java.net.HttpURLConnection.HTTP_PARTIAL;
19+
import static java.net.HttpURLConnection.HTTP_SEE_OTHER;
1620

1721
/**
1822
* {@link Source} that uses http resource as source for {@link ProxyCache}.
@@ -21,7 +25,8 @@
2125
*/
2226
public class HttpUrlSource implements Source {
2327

24-
public String url;
28+
private static final int MAX_REDIRECTS = 5;
29+
public final String url;
2530
private HttpURLConnection connection;
2631
private InputStream inputStream;
2732
private volatile int available = Integer.MIN_VALUE;
@@ -47,33 +52,10 @@ public synchronized int available() throws ProxyCacheException {
4752
@Override
4853
public void open(int offset) throws ProxyCacheException {
4954
try {
50-
boolean isRedirected;
51-
int redirectCount = 0;
52-
int responseCode;
53-
do {
54-
Log.d(ProxyCacheUtils.LOG_TAG, "Open connection " + (offset > 0 ? " with offset " + offset : "") + " to " + url);
55-
connection = (HttpURLConnection) new URL(url).openConnection();
56-
if (offset > 0) {
57-
connection.setRequestProperty("Range", "bytes=" + offset + "-");
58-
}
59-
responseCode = connection.getResponseCode();
60-
if ((responseCode == HttpURLConnection.HTTP_MOVED_PERM
61-
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP
62-
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER)) {
63-
url = connection.getHeaderField("Location");
64-
isRedirected = true;
65-
redirectCount++;
66-
} else {
67-
isRedirected = false;
68-
}
69-
if (redirectCount > ProxyCacheUtils.MAX_REDIRECTS) {
70-
throw new ProxyCacheException("Too many redirects");
71-
}
72-
} while (isRedirected);
73-
55+
connection = openConnection(offset, "GET", -1);
7456
mime = connection.getContentType();
7557
inputStream = new BufferedInputStream(connection.getInputStream(), DEFAULT_BUFFER_SIZE);
76-
available = readSourceAvailableBytes(connection, offset, responseCode);
58+
available = readSourceAvailableBytes(connection, offset, connection.getResponseCode());
7759
} catch (IOException e) {
7860
throw new ProxyCacheException("Error opening connection for " + url + " with offset " + offset, e);
7961
}
@@ -111,28 +93,7 @@ private void fetchContentInfo() throws ProxyCacheException {
11193
HttpURLConnection urlConnection = null;
11294
InputStream inputStream = null;
11395
try {
114-
boolean isRedirected;
115-
int redirectCount = 0;
116-
do {
117-
urlConnection = (HttpURLConnection) new URL(url).openConnection();
118-
urlConnection.setConnectTimeout(10000);
119-
urlConnection.setReadTimeout(10000);
120-
urlConnection.setRequestMethod("HEAD");
121-
int responseCode = urlConnection.getResponseCode();
122-
if ((responseCode == HttpURLConnection.HTTP_MOVED_PERM
123-
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP
124-
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER)) {
125-
url = urlConnection.getHeaderField("Location");
126-
isRedirected = true;
127-
redirectCount++;
128-
} else {
129-
isRedirected = false;
130-
}
131-
if (redirectCount > ProxyCacheUtils.MAX_REDIRECTS) {
132-
throw new ProxyCacheException("Too many redirects");
133-
}
134-
} while (isRedirected);
135-
96+
urlConnection = openConnection(0, "HEAD", 10000);
13697
available = urlConnection.getContentLength();
13798
mime = urlConnection.getContentType();
13899
inputStream = urlConnection.getInputStream();
@@ -147,13 +108,47 @@ private void fetchContentInfo() throws ProxyCacheException {
147108
}
148109
}
149110

111+
private HttpURLConnection openConnection(int offset, String method, int timeout) throws IOException, ProxyCacheException {
112+
HttpURLConnection connection;
113+
boolean redirected;
114+
int redirectCount = 0;
115+
String url = this.url;
116+
do {
117+
Log.d(LOG_TAG, "Open connection " + (offset > 0 ? " with offset " + offset : "") + " to " + url);
118+
connection = (HttpURLConnection) new URL(url).openConnection();
119+
connection.setRequestMethod(method);
120+
if (offset > 0) {
121+
connection.setRequestProperty("Range", "bytes=" + offset + "-");
122+
}
123+
if (timeout > 0) {
124+
connection.setConnectTimeout(timeout);
125+
connection.setReadTimeout(timeout);
126+
}
127+
int code = connection.getResponseCode();
128+
redirected = code == HTTP_MOVED_PERM || code == HTTP_MOVED_TEMP || code == HTTP_SEE_OTHER;
129+
if (redirected) {
130+
url = connection.getHeaderField("Location");
131+
redirectCount++;
132+
connection.disconnect();
133+
}
134+
if (redirectCount > MAX_REDIRECTS) {
135+
throw new ProxyCacheException("Too many redirects: " + redirectCount);
136+
}
137+
} while (redirected);
138+
return connection;
139+
}
140+
150141
public synchronized String getMime() throws ProxyCacheException {
151142
if (TextUtils.isEmpty(mime)) {
152143
fetchContentInfo();
153144
}
154145
return mime;
155146
}
156147

148+
public String getUrl() {
149+
return url;
150+
}
151+
157152
@Override
158153
public String toString() {
159154
return "HttpUrlSource{url='" + url + "}";

library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class ProxyCacheUtils {
2525
static final String LOG_TAG = "ProxyCache";
2626
static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
2727
static final int MAX_ARRAY_PREVIEW = 16;
28-
static final int MAX_REDIRECTS = 5;
2928

3029
static String getSupposablyMime(String url) {
3130
MimeTypeMap mimes = MimeTypeMap.getSingleton();

sample/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ apply plugin: 'com.neenbedankt.android-apt'
1717

1818
android {
1919
compileSdkVersion 23
20-
buildToolsVersion '23.0.0'
20+
buildToolsVersion '23.0.1'
2121

2222
defaultConfig {
2323
applicationId "com.danikula.videocache.sample"
@@ -37,9 +37,9 @@ apt {
3737

3838
dependencies {
3939
// compile project(':library')
40-
compile 'com.android.support:support-v4:23.0.0'
40+
compile 'com.android.support:support-v4:23.0.1'
4141
compile 'org.androidannotations:androidannotations-api:3.3.2'
42-
compile 'com.danikula:videocache:2.0.9'
42+
compile 'com.danikula:videocache:2.1.0'
4343
compile 'com.viewpagerindicator:library:2.4.2-SNAPSHOT@aar'
4444
apt 'org.androidannotations:androidannotations:3.3.2'
4545
}

test/src/test/java/com/danikula/videocache/HttpProxyCacheServerTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static com.danikula.videocache.support.ProxyCacheTestUtils.ASSETS_DATA_NAME;
2222
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_BIG_SIZE;
2323
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_BIG_URL;
24+
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_BIG_URL_ONE_REDIRECT;
2425
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL;
2526
import static com.danikula.videocache.support.ProxyCacheTestUtils.getFileContent;
2627
import static com.danikula.videocache.support.ProxyCacheTestUtils.loadAssetFile;
@@ -81,6 +82,20 @@ public void testProxyFullResponse() throws Exception {
8182
assertThat(response.second.data).isEqualTo(loadAssetFile(ASSETS_DATA_BIG_NAME));
8283
}
8384

85+
@Test
86+
public void testProxyFullResponseWithRedirect() throws Exception {
87+
Pair<File, Response> response = readProxyData(HTTP_DATA_BIG_URL_ONE_REDIRECT);
88+
89+
assertThat(response.second.code).isEqualTo(200);
90+
assertThat(response.second.contentLength).isEqualTo(HTTP_DATA_BIG_SIZE);
91+
assertThat(response.second.contentType).isEqualTo("image/jpeg");
92+
assertThat(response.second.headers.containsKey("Accept-Ranges")).isTrue();
93+
assertThat(response.second.headers.get("Accept-Ranges").get(0)).isEqualTo("bytes");
94+
assertThat(response.second.headers.containsKey("Content-Range")).isFalse();
95+
assertThat(response.second.data).isEqualTo(getFileContent(response.first));
96+
assertThat(response.second.data).isEqualTo(loadAssetFile(ASSETS_DATA_BIG_NAME));
97+
}
98+
8499
@Test
85100
public void testProxyPartialResponse() throws Exception {
86101
int offset = 42000;
@@ -99,6 +114,24 @@ public void testProxyPartialResponse() throws Exception {
99114
assertThat(getFileContent(response.first)).isEqualTo(loadAssetFile(ASSETS_DATA_BIG_NAME));
100115
}
101116

117+
@Test
118+
public void testProxyPartialResponseWithRedirect() throws Exception {
119+
int offset = 42000;
120+
Pair<File, Response> response = readProxyData(HTTP_DATA_BIG_URL_ONE_REDIRECT, offset);
121+
122+
assertThat(response.second.code).isEqualTo(206);
123+
assertThat(response.second.contentLength).isEqualTo(HTTP_DATA_BIG_SIZE - offset);
124+
assertThat(response.second.contentType).isEqualTo("image/jpeg");
125+
assertThat(response.second.headers.containsKey("Accept-Ranges")).isTrue();
126+
assertThat(response.second.headers.get("Accept-Ranges").get(0)).isEqualTo("bytes");
127+
assertThat(response.second.headers.containsKey("Content-Range")).isTrue();
128+
String rangeHeader = String.format("bytes %d-%d/%d", offset, HTTP_DATA_BIG_SIZE, HTTP_DATA_BIG_SIZE);
129+
assertThat(response.second.headers.get("Content-Range").get(0)).isEqualTo(rangeHeader);
130+
byte[] expectedData = Arrays.copyOfRange(loadAssetFile(ASSETS_DATA_BIG_NAME), offset, HTTP_DATA_BIG_SIZE);
131+
assertThat(response.second.data).isEqualTo(expectedData);
132+
assertThat(getFileContent(response.first)).isEqualTo(loadAssetFile(ASSETS_DATA_BIG_NAME));
133+
}
134+
102135
private Pair<File, Response> readProxyData(String url, int offset) throws IOException {
103136
File externalCacheDir = RuntimeEnvironment.application.getExternalCacheDir();
104137
FileNameGenerator fileNameGenerator = new Md5FileNameGenerator(externalCacheDir);

test/src/test/java/com/danikula/videocache/HttpUrlSourceTest.java

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
package com.danikula.videocache;
22

33
import com.danikula.videocache.test.BuildConfig;
4-
import java.io.ByteArrayOutputStream;
5-
import java.util.Arrays;
4+
65
import org.junit.Ignore;
76
import org.junit.Test;
87
import org.junit.runner.RunWith;
98
import org.robolectric.RobolectricGradleTestRunner;
109
import org.robolectric.annotation.Config;
1110

11+
import java.io.ByteArrayOutputStream;
12+
import java.util.Arrays;
13+
1214
import static com.danikula.videocache.support.ProxyCacheTestUtils.ASSETS_DATA_BIG_NAME;
1315
import static com.danikula.videocache.support.ProxyCacheTestUtils.ASSETS_DATA_NAME;
1416
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_BIG_SIZE;
1517
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_BIG_URL;
18+
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_SIZE;
1619
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL;
20+
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL_3_REDIRECTS;
21+
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL_6_REDIRECTS;
22+
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL_ONE_REDIRECT;
1723
import static com.danikula.videocache.support.ProxyCacheTestUtils.loadAssetFile;
1824
import static org.fest.assertions.api.Assertions.assertThat;
25+
import static org.fest.assertions.api.Assertions.fail;
1926

2027
/**
2128
* @author Alexey Danilov (danikula@gmail.com).
@@ -59,15 +66,68 @@ public void testFetchContentLength() throws Exception {
5966
assertThat(source.available()).isEqualTo(loadAssetFile(ASSETS_DATA_NAME).length);
6067
}
6168

69+
@Test
70+
public void testFetchInfoWithRedirect() throws Exception {
71+
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_ONE_REDIRECT);
72+
source.open(0);
73+
int available = source.available();
74+
String mime = source.getMime();
75+
source.close();
76+
77+
assertThat(available).isEqualTo(HTTP_DATA_SIZE);
78+
assertThat(mime).isEqualTo("image/jpeg");
79+
}
80+
81+
@Test
82+
public void testFetchDataWithRedirect() throws Exception {
83+
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_ONE_REDIRECT);
84+
source.open(0);
85+
byte[] readData = new byte[HTTP_DATA_SIZE];
86+
source.read(readData);
87+
source.close();
88+
89+
byte[] expectedData = Arrays.copyOfRange(loadAssetFile(ASSETS_DATA_NAME), 0, HTTP_DATA_SIZE);
90+
assertThat(readData).isEqualTo(expectedData);
91+
}
92+
93+
@Test
94+
public void testFetchPartialDataWithRedirect() throws Exception {
95+
int offset = 42;
96+
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_ONE_REDIRECT);
97+
source.open(offset);
98+
byte[] readData = new byte[HTTP_DATA_SIZE - offset];
99+
source.read(readData);
100+
source.close();
101+
102+
byte[] expectedData = Arrays.copyOfRange(loadAssetFile(ASSETS_DATA_NAME), offset, HTTP_DATA_SIZE);
103+
assertThat(readData).isEqualTo(expectedData);
104+
}
105+
106+
@Test
107+
public void testFetchPartialDataWithMultiRedirects() throws Exception {
108+
int offset = 42;
109+
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_3_REDIRECTS);
110+
source.open(offset);
111+
byte[] readData = new byte[HTTP_DATA_SIZE - offset];
112+
source.read(readData);
113+
source.close();
114+
115+
byte[] expectedData = Arrays.copyOfRange(loadAssetFile(ASSETS_DATA_NAME), offset, HTTP_DATA_SIZE);
116+
assertThat(readData).isEqualTo(expectedData);
117+
}
118+
119+
@Ignore("To test it fairly we should disable caching connection.setUseCaches(false), but it will decrease performance")
120+
@Test(expected = ProxyCacheException.class)
121+
public void testExceedingRedirects() throws Exception {
122+
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_6_REDIRECTS);
123+
source.open(0);
124+
fail("Too many redirects");
125+
}
126+
62127
@Ignore("Seems Robolectric bug: MimeTypeMap.getFileExtensionFromUrl always returns null")
63128
@Test
64129
public void testMimeByUrl() throws Exception {
65130
assertThat(new HttpUrlSource("http://mysite.by/video.mp4").getMime()).isEqualTo("video/mp4");
66131
assertThat(new HttpUrlSource(HTTP_DATA_URL).getMime()).isEqualTo("image/jpeg");
67132
}
68-
69-
@Test
70-
public void testHttpUrlSourceRedirect() throws Exception {
71-
assertThat(new HttpUrlSource("http://goo.gl/K0gWQW").getMime()).isEqualTo("video/mp4");
72-
}
73133
}

test/src/test/java/com/danikula/videocache/support/ProxyCacheTestUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
public class ProxyCacheTestUtils {
2222

2323
public static final String HTTP_DATA_URL = "https://dl.dropboxusercontent.com/u/15506779/persistent/proxycache/android.jpg";
24+
public static final String HTTP_DATA_URL_ONE_REDIRECT = "http://bit.ly/1V5PeY5";
25+
public static final String HTTP_DATA_URL_3_REDIRECTS = "http://bit.ly/1KvVmgZ";
26+
public static final String HTTP_DATA_URL_6_REDIRECTS = "http://ow.ly/SugRH";
2427
public static final String HTTP_DATA_BIG_URL = "https://dl.dropboxusercontent.com/u/15506779/persistent/proxycache/phones.jpg";
28+
public static final String HTTP_DATA_BIG_URL_ONE_REDIRECT = "http://bit.ly/1iJ69yA";
2529
public static final String ASSETS_DATA_NAME = "android.jpg";
2630
public static final String ASSETS_DATA_BIG_NAME = "phones.jpg";
2731
public static final int HTTP_DATA_SIZE = 4768;

0 commit comments

Comments
 (0)