mirror of
https://github.com/zhigang1992/AndroidVideoCache.git
synced 2026-03-06 22:32:57 +08:00
🎉 fix #28: ignore system proxy for localhost requests
This commit is contained in:
@@ -73,6 +73,7 @@ public class HttpProxyCacheServer {
|
||||
InetAddress inetAddress = InetAddress.getByName(PROXY_HOST);
|
||||
this.serverSocket = new ServerSocket(0, 8, inetAddress);
|
||||
this.port = serverSocket.getLocalPort();
|
||||
IgnoreHostProxySelector.install(PROXY_HOST, port);
|
||||
CountDownLatch startSignal = new CountDownLatch(1);
|
||||
this.waitConnectionThread = new Thread(new WaitRequestsRunnable(startSignal));
|
||||
this.waitConnectionThread.start();
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.danikula.videocache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.danikula.videocache.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* {@link ProxySelector} that ignore system default proxies for concrete host.
|
||||
* <p>
|
||||
* It is important to <a href="https://github.com/danikula/AndroidVideoCache/issues/28">ignore system proxy</a> for localhost connection.
|
||||
*
|
||||
* @author Alexey Danilov (danikula@gmail.com).
|
||||
*/
|
||||
class IgnoreHostProxySelector extends ProxySelector {
|
||||
|
||||
private static final List<Proxy> NO_PROXY_LIST = Arrays.asList(Proxy.NO_PROXY);
|
||||
|
||||
private final ProxySelector defaultProxySelector;
|
||||
private final String hostToIgnore;
|
||||
private final int portToIgnore;
|
||||
|
||||
IgnoreHostProxySelector(ProxySelector defaultProxySelector, String hostToIgnore, int portToIgnore) {
|
||||
this.defaultProxySelector = checkNotNull(defaultProxySelector);
|
||||
this.hostToIgnore = checkNotNull(hostToIgnore);
|
||||
this.portToIgnore = portToIgnore;
|
||||
}
|
||||
|
||||
static void install(String hostToIgnore, int portToIgnore) {
|
||||
ProxySelector defaultProxySelector = ProxySelector.getDefault();
|
||||
ProxySelector ignoreHostProxySelector = new IgnoreHostProxySelector(defaultProxySelector, hostToIgnore, portToIgnore);
|
||||
ProxySelector.setDefault(ignoreHostProxySelector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Proxy> select(URI uri) {
|
||||
boolean ignored = hostToIgnore.equals(uri.getHost()) && portToIgnore == uri.getPort();
|
||||
List<Proxy> proxies = ignored ? NO_PROXY_LIST : defaultProxySelector.select(uri);
|
||||
return proxies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectFailed(URI uri, SocketAddress address, IOException failure) {
|
||||
defaultProxySelector.connectFailed(uri, address, failure);
|
||||
}
|
||||
}
|
||||
@@ -75,9 +75,9 @@ class Pinger {
|
||||
}
|
||||
|
||||
private List<Proxy> getDefaultProxies() {
|
||||
ProxySelector proxySelector = ProxySelector.getDefault();
|
||||
try {
|
||||
return proxySelector.select(new URI("https://github.com"));
|
||||
ProxySelector defaultProxySelector = ProxySelector.getDefault();
|
||||
return defaultProxySelector.select(new URI(getPingUrl()));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.danikula.videocache.file.Md5FileNameGenerator;
|
||||
import com.danikula.videocache.support.ProxyCacheTestUtils;
|
||||
import com.danikula.videocache.support.Response;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
@@ -31,8 +33,11 @@ import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL_
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL_ONE_REDIRECT;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.getFileContent;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.getPort;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.getPortWithoutPing;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.installExternalSystemProxy;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.loadAssetFile;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.readProxyResponse;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.resetSystemProxy;
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -47,6 +52,7 @@ public class HttpProxyCacheServerTest extends BaseTest {
|
||||
cacheFolder = ProxyCacheTestUtils.newCacheFile();
|
||||
createDirectory(cacheFolder);
|
||||
cleanDirectory(cacheFolder);
|
||||
resetSystemProxy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -338,6 +344,25 @@ public class HttpProxyCacheServerTest extends BaseTest {
|
||||
assertThat(new File(cacheFolder, fileNameGenerator.generate(HTTP_DATA_URL))).doesNotExist();
|
||||
}
|
||||
|
||||
@Test // https://github.com/danikula/AndroidVideoCache/issues/28
|
||||
public void testWorkWithExternalProxy() throws Exception {
|
||||
installExternalSystemProxy();
|
||||
|
||||
Pair<File, Response> response = readProxyData(HTTP_DATA_URL, 0);
|
||||
assertThat(response.second.data).isEqualTo(loadAssetFile(ASSETS_DATA_NAME));
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class) // https://github.com/danikula/AndroidVideoCache/issues/28
|
||||
public void testDoesNotWorkWithoutCustomProxySelector() throws Exception {
|
||||
HttpProxyCacheServer httpProxyCacheServer = new HttpProxyCacheServer(RuntimeEnvironment.application);
|
||||
// IgnoreHostProxySelector is set in HttpProxyCacheServer constructor. So let reset it by custom.
|
||||
installExternalSystemProxy();
|
||||
|
||||
String proxiedUrl = "http://127.0.0.1:" + getPortWithoutPing(httpProxyCacheServer) + "/" + HTTP_DATA_URL;
|
||||
readProxyResponse(httpProxyCacheServer, proxiedUrl);
|
||||
Assert.fail(); // should throw IOException on the previous line
|
||||
}
|
||||
|
||||
private Pair<File, Response> readProxyData(String url, int offset) throws IOException {
|
||||
File file = file(cacheFolder, url);
|
||||
HttpProxyCacheServer proxy = newProxy(cacheFolder);
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
package com.danikula.videocache;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.HTTP_DATA_URL;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.getPort;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.getPortWithoutPing;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.installExternalSystemProxy;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.readProxyResponse;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.resetSystemProxy;
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -18,6 +27,11 @@ import static org.mockito.Mockito.when;
|
||||
*/
|
||||
public class PingerTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
resetSystemProxy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPingSuccess() throws Exception {
|
||||
HttpProxyCacheServer server = new HttpProxyCacheServer(RuntimeEnvironment.application);
|
||||
@@ -52,5 +66,23 @@ public class PingerTest extends BaseTest {
|
||||
assertThat(out.toString()).isEqualTo("HTTP/1.1 200 OK\n\nping ok");
|
||||
}
|
||||
|
||||
@Test // https://github.com/danikula/AndroidVideoCache/issues/28
|
||||
public void testPingedWithExternalProxy() throws Exception {
|
||||
installExternalSystemProxy();
|
||||
|
||||
HttpProxyCacheServer server = new HttpProxyCacheServer(RuntimeEnvironment.application);
|
||||
Pinger pinger = new Pinger("127.0.0.1", getPortWithoutPing(server));
|
||||
assertThat(pinger.ping(1, 100)).isTrue();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class) // https://github.com/danikula/AndroidVideoCache/issues/28
|
||||
public void testIsNotPingedWithoutCustomProxySelector() throws Exception {
|
||||
HttpProxyCacheServer httpProxyCacheServer = new HttpProxyCacheServer(RuntimeEnvironment.application);
|
||||
// IgnoreHostProxySelector is set in HttpProxyCacheServer constructor. So let reset it by custom.
|
||||
installExternalSystemProxy();
|
||||
|
||||
String proxiedUrl = "http://127.0.0.1:" + getPortWithoutPing(httpProxyCacheServer) + "/" + HTTP_DATA_URL;
|
||||
readProxyResponse(httpProxyCacheServer, proxiedUrl);
|
||||
Assert.fail(); // should throw IOException on the previous line
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.danikula.videocache;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.resetSystemProxy;
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests {@link IgnoreHostProxySelector}.
|
||||
*
|
||||
* @author Alexey Danilov (danikula@gmail.com).
|
||||
*/
|
||||
public class ProxySelectorTest extends BaseTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
resetSystemProxy();
|
||||
}
|
||||
|
||||
@Test // https://github.com/danikula/AndroidVideoCache/issues/28
|
||||
public void testIgnoring() throws Exception {
|
||||
InetSocketAddress proxyAddress = new InetSocketAddress("proxy.com", 80);
|
||||
Proxy systemProxy = new Proxy(Proxy.Type.HTTP, proxyAddress);
|
||||
ProxySelector mockedProxySelector = Mockito.mock(ProxySelector.class);
|
||||
when(mockedProxySelector.select(Mockito.<URI>any())).thenReturn(Lists.newArrayList(systemProxy));
|
||||
ProxySelector.setDefault(mockedProxySelector);
|
||||
|
||||
IgnoreHostProxySelector.install("localhost", 42);
|
||||
|
||||
ProxySelector proxySelector = ProxySelector.getDefault();
|
||||
List<Proxy> githubProxies = proxySelector.select(new URI("http://github.com"));
|
||||
assertThat(githubProxies).hasSize(1);
|
||||
assertThat(githubProxies.get(0).address()).isEqualTo(proxyAddress);
|
||||
|
||||
List<Proxy> localhostProxies = proxySelector.select(new URI("http://localhost:42"));
|
||||
assertThat(localhostProxies).hasSize(1);
|
||||
assertThat(localhostProxies.get(0)).isEqualTo(Proxy.NO_PROXY);
|
||||
|
||||
List<Proxy> localhostPort69Proxies = proxySelector.select(new URI("http://localhost:69"));
|
||||
assertThat(localhostPort69Proxies).hasSize(1);
|
||||
assertThat(localhostPort69Proxies.get(0).address()).isEqualTo(proxyAddress);
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,11 @@ import com.danikula.videocache.HttpUrlSource;
|
||||
import com.danikula.videocache.ProxyCacheException;
|
||||
import com.danikula.videocache.Source;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import org.apache.tools.ant.util.ReflectUtil;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
@@ -18,6 +21,10 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
@@ -31,6 +38,7 @@ import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Alexey Danilov (danikula@gmail.com).
|
||||
@@ -147,4 +155,22 @@ public class ProxyCacheTestUtils {
|
||||
String portAsString = matcher.group(1);
|
||||
return Integer.parseInt(portAsString);
|
||||
}
|
||||
|
||||
public static int getPortWithoutPing(HttpProxyCacheServer server) {
|
||||
return (Integer) ReflectUtil.getField(server, "port");
|
||||
}
|
||||
|
||||
public static void installExternalSystemProxy() {
|
||||
// see proxies list at http://proxylist.hidemyass.com/
|
||||
Proxy systemProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("162.8.230.7", 11180));
|
||||
ProxySelector mockedProxySelector = Mockito.mock(ProxySelector.class);
|
||||
when(mockedProxySelector.select(Mockito.<URI>any())).thenReturn(Lists.newArrayList(systemProxy));
|
||||
ProxySelector.setDefault(mockedProxySelector);
|
||||
}
|
||||
|
||||
public static void resetSystemProxy() {
|
||||
ProxySelector mockedProxySelector = Mockito.mock(ProxySelector.class);
|
||||
when(mockedProxySelector.select(Mockito.<URI>any())).thenReturn(Lists.newArrayList(Proxy.NO_PROXY));
|
||||
ProxySelector.setDefault(mockedProxySelector);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user