Skip to content

Commit acdf747

Browse files
lucas34danikula
authored andcommitted
#20: headers injector
1 parent 89ab593 commit acdf747

9 files changed

Lines changed: 127 additions & 3 deletions

File tree

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- [Disk cache limit](#disk-cache-limit)
1010
- [Listen caching progress](#listen-caching-progress)
1111
- [Providing names for cached files](#providing-names-for-cached-files)
12+
- [Adding custom http headers](#adding-custom-http-headers)
1213
- [Using exoPlayer](#using-exoplayer)
1314
- [Sample](#sample)
1415
- [Known problems](#known-problems)
@@ -137,6 +138,25 @@ HttpProxyCacheServer proxy = HttpProxyCacheServer.Builder(context)
137138
.build()
138139
```
139140

141+
### Adding custom http headers
142+
You can add custom headers to requests with help of `HeadersInjector`:
143+
``` java
144+
public class UserAgentHeadersInjector implements HeaderInjector {
145+
146+
@Override
147+
public Map<String, String> addHeaders(String url) {
148+
return Maps.newHashMap("User-Agent", "Cool app v1.1");
149+
}
150+
}
151+
152+
private HttpProxyCacheServer newProxy() {
153+
return new HttpProxyCacheServer.Builder(this)
154+
.headerInjector(new UserAgentHeadersInjector())
155+
.build();
156+
}
157+
158+
```
159+
140160
### Using exoPlayer
141161
You can use [`exoPlayer`](https://google.github.io/ExoPlayer/) with `AndroidVideoCache`. See `sample` app in [`exoPlayer`](https://github.com/danikula/AndroidVideoCache/tree/exoPlayer) branch. Note [exoPlayer supports](https://github.com/google/ExoPlayer/commit/bd7be1b5e7cc41a59ebbc348d394820fc857db92) cache as well.
142162

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.danikula.videocache.file.DiskUsage;
44
import com.danikula.videocache.file.FileNameGenerator;
5+
import com.danikula.videocache.headers.HeaderInjector;
56
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
67

78
import java.io.File;
@@ -17,12 +18,14 @@ class Config {
1718
public final FileNameGenerator fileNameGenerator;
1819
public final DiskUsage diskUsage;
1920
public final SourceInfoStorage sourceInfoStorage;
21+
public final HeaderInjector headerInjector;
2022

21-
Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage, SourceInfoStorage sourceInfoStorage) {
23+
Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage, SourceInfoStorage sourceInfoStorage, HeaderInjector headerInjector) {
2224
this.cacheRoot = cacheRoot;
2325
this.fileNameGenerator = fileNameGenerator;
2426
this.diskUsage = diskUsage;
2527
this.sourceInfoStorage = sourceInfoStorage;
28+
this.headerInjector = headerInjector;
2629
}
2730

2831
File generateCacheFile(String url) {

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import com.danikula.videocache.file.Md5FileNameGenerator;
99
import com.danikula.videocache.file.TotalCountLruDiskUsage;
1010
import com.danikula.videocache.file.TotalSizeLruDiskUsage;
11+
import com.danikula.videocache.headers.EmptyHeadersInjector;
12+
import com.danikula.videocache.headers.HeaderInjector;
1113
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
1214
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
1315

@@ -350,12 +352,14 @@ public static final class Builder {
350352
private FileNameGenerator fileNameGenerator;
351353
private DiskUsage diskUsage;
352354
private SourceInfoStorage sourceInfoStorage;
355+
private HeaderInjector headerInjector;
353356

354357
public Builder(Context context) {
355358
this.sourceInfoStorage = SourceInfoStorageFactory.newSourceInfoStorage(context);
356359
this.cacheRoot = StorageUtils.getIndividualCacheDirectory(context);
357360
this.diskUsage = new TotalSizeLruDiskUsage(DEFAULT_MAX_SIZE);
358361
this.fileNameGenerator = new Md5FileNameGenerator();
362+
this.headerInjector = new EmptyHeadersInjector();
359363
}
360364

361365
/**
@@ -426,6 +430,17 @@ public Builder diskUsage(DiskUsage diskUsage) {
426430
return this;
427431
}
428432

433+
/**
434+
* Add headers along the request to the server
435+
*
436+
* @param headerInjector to inject header base on url
437+
* @return a builder
438+
*/
439+
public Builder headerInjector(HeaderInjector headerInjector) {
440+
this.headerInjector = checkNotNull(headerInjector);
441+
return this;
442+
}
443+
429444
/**
430445
* Builds new instance of {@link HttpProxyCacheServer}.
431446
*
@@ -437,7 +452,7 @@ public HttpProxyCacheServer build() {
437452
}
438453

439454
private Config buildConfig() {
440-
return new Config(cacheRoot, fileNameGenerator, diskUsage, sourceInfoStorage);
455+
return new Config(cacheRoot, fileNameGenerator, diskUsage, sourceInfoStorage, headerInjector);
441456
}
442457

443458
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public int getClientsCount() {
7979
}
8080

8181
private HttpProxyCache newHttpProxyCache() throws ProxyCacheException {
82-
HttpUrlSource source = new HttpUrlSource(url, config.sourceInfoStorage);
82+
HttpUrlSource source = new HttpUrlSource(url, config.sourceInfoStorage, config.headerInjector);
8383
FileCache cache = new FileCache(config.generateCacheFile(url), config.diskUsage);
8484
HttpProxyCache httpProxyCache = new HttpProxyCache(source, cache);
8585
httpProxyCache.registerCacheListener(uiCacheListener);

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import android.text.TextUtils;
44

5+
import com.danikula.videocache.headers.EmptyHeadersInjector;
6+
import com.danikula.videocache.headers.HeaderInjector;
57
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
68
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
79

@@ -14,6 +16,7 @@
1416
import java.io.InterruptedIOException;
1517
import java.net.HttpURLConnection;
1618
import java.net.URL;
19+
import java.util.Map;
1720

1821
import static com.danikula.videocache.Preconditions.checkNotNull;
1922
import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE;
@@ -34,6 +37,7 @@ public class HttpUrlSource implements Source {
3437

3538
private static final int MAX_REDIRECTS = 5;
3639
private final SourceInfoStorage sourceInfoStorage;
40+
private final HeaderInjector headerInjector;
3741
private SourceInfo sourceInfo;
3842
private HttpURLConnection connection;
3943
private InputStream inputStream;
@@ -43,7 +47,12 @@ public HttpUrlSource(String url) {
4347
}
4448

4549
public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage) {
50+
this(url, sourceInfoStorage, new EmptyHeadersInjector());
51+
}
52+
53+
public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage, HeaderInjector headerInjector) {
4654
this.sourceInfoStorage = checkNotNull(sourceInfoStorage);
55+
this.headerInjector = checkNotNull(headerInjector);
4756
SourceInfo sourceInfo = sourceInfoStorage.get(url);
4857
this.sourceInfo = sourceInfo != null ? sourceInfo :
4958
new SourceInfo(url, Integer.MIN_VALUE, ProxyCacheUtils.getSupposablyMime(url));
@@ -52,6 +61,7 @@ public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage) {
5261
public HttpUrlSource(HttpUrlSource source) {
5362
this.sourceInfo = source.sourceInfo;
5463
this.sourceInfoStorage = source.sourceInfoStorage;
64+
this.headerInjector = source.headerInjector;
5565
}
5666

5767
@Override
@@ -150,6 +160,7 @@ private HttpURLConnection openConnection(long offset, int timeout) throws IOExce
150160
do {
151161
LOG.debug("Open connection " + (offset > 0 ? " with offset " + offset : "") + " to " + url);
152162
connection = (HttpURLConnection) new URL(url).openConnection();
163+
injectCustomHeaders(connection, url);
153164
if (offset > 0) {
154165
connection.setRequestProperty("Range", "bytes=" + offset + "-");
155166
}
@@ -171,6 +182,13 @@ private HttpURLConnection openConnection(long offset, int timeout) throws IOExce
171182
return connection;
172183
}
173184

185+
private void injectCustomHeaders(HttpURLConnection connection, String url) {
186+
Map<String, String> extraHeaders = headerInjector.addHeaders(url);
187+
for (Map.Entry<String, String> header : extraHeaders.entrySet()) {
188+
connection.setRequestProperty(header.getKey(), header.getValue());
189+
}
190+
}
191+
174192
public synchronized String getMime() throws ProxyCacheException {
175193
if (TextUtils.isEmpty(sourceInfo.mime)) {
176194
fetchContentInfo();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.danikula.videocache.headers;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
/**
7+
* Empty {@link HeaderInjector} implementation.
8+
*
9+
* @author Lucas Nelaupe (https://github.com/lucas34).
10+
*/
11+
public class EmptyHeadersInjector implements HeaderInjector {
12+
13+
@Override
14+
public Map<String, String> addHeaders(String url) {
15+
return new HashMap<>();
16+
}
17+
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.danikula.videocache.headers;
2+
3+
import java.util.Map;
4+
5+
/**
6+
* Allows to add custom headers to server's requests.
7+
*
8+
* @author Lucas Nelaupe (https://github.com/lucas34).
9+
*/
10+
public interface HeaderInjector {
11+
12+
/**
13+
* Adds headers to server's requests for corresponding url.
14+
*
15+
* @param url an url headers will be added for
16+
* @return a map with headers, where keys are header's names, and values are header's values. {@code null} is not acceptable!
17+
*/
18+
Map<String, String> addHeaders(String url);
19+
20+
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import com.danikula.android.garden.io.IoUtils;
77
import com.danikula.videocache.file.FileNameGenerator;
88
import com.danikula.videocache.file.Md5FileNameGenerator;
9+
import com.danikula.videocache.headers.HeaderInjector;
910
import com.danikula.videocache.support.ProxyCacheTestUtils;
1011
import com.danikula.videocache.support.Response;
1112

1213
import org.junit.Before;
1314
import org.junit.Test;
15+
import org.mockito.Mockito;
1416
import org.robolectric.RuntimeEnvironment;
1517

1618
import java.io.File;
@@ -36,6 +38,8 @@
3638
import static com.danikula.videocache.support.ProxyCacheTestUtils.readProxyResponse;
3739
import static com.danikula.videocache.support.ProxyCacheTestUtils.resetSystemProxy;
3840
import static org.fest.assertions.api.Assertions.assertThat;
41+
import static org.mockito.Mockito.times;
42+
import static org.mockito.Mockito.verify;
3943

4044
/**
4145
* @author Alexey Danilov (danikula@gmail.com).
@@ -360,6 +364,20 @@ public void testDoesNotWorkWithoutCustomProxySelector() throws Exception {
360364
assertThat(proxiedUrl).isEqualTo(HTTP_DATA_URL);
361365
}
362366

367+
@Test
368+
public void testHeadersInjectorIsInvoked() throws Exception {
369+
HeaderInjector mockedHeaderInjector = Mockito.mock(HeaderInjector.class);
370+
371+
HttpProxyCacheServer proxy = new HttpProxyCacheServer.Builder(RuntimeEnvironment.application)
372+
.headerInjector(mockedHeaderInjector)
373+
.build();
374+
375+
readProxyResponse(proxy, HTTP_DATA_URL);
376+
proxy.shutdown();
377+
378+
verify(mockedHeaderInjector, times(2)).addHeaders(HTTP_DATA_URL); // content info & fetch data requests
379+
}
380+
363381
private Pair<File, Response> readProxyData(String url, int offset) throws IOException {
364382
File file = file(cacheFolder, url);
365383
HttpProxyCacheServer proxy = newProxy(cacheFolder);

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.danikula.videocache;
22

3+
import com.danikula.videocache.headers.HeaderInjector;
34
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
45
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
56
import com.danikula.videocache.support.ProxyCacheTestUtils;
@@ -25,6 +26,7 @@
2526
import static org.fest.assertions.api.Assertions.assertThat;
2627
import static org.fest.assertions.api.Assertions.fail;
2728
import static org.mockito.Matchers.any;
29+
import static org.mockito.Mockito.when;
2830

2931
/**
3032
* @author Alexey Danilov (danikula@gmail.com).
@@ -156,6 +158,16 @@ public void testNotOpenableHttpUrlSourceOpen() throws Exception {
156158
fail("source.open() should throw exception");
157159
}
158160

161+
@Test(expected = NullPointerException.class)
162+
public void testHeaderInjectorNullNotAcceptable() throws Exception {
163+
HeaderInjector mockedHeaderInjector = Mockito.mock(HeaderInjector.class);
164+
when(mockedHeaderInjector.addHeaders(Mockito.anyString())).thenReturn(null);
165+
SourceInfoStorage emptySourceInfoStorage = SourceInfoStorageFactory.newEmptySourceInfoStorage();
166+
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_ONE_REDIRECT, emptySourceInfoStorage, mockedHeaderInjector);
167+
source.open(0);
168+
fail("source.open should throw NPE!");
169+
}
170+
159171
private void readSource(Source source, byte[] target) throws ProxyCacheException {
160172
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
161173
int totalRead = 0;

0 commit comments

Comments
 (0)