package com.limegroup.gnutella.uploader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import junit.framework.AssertionFailedError; import junit.framework.Test; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicHeader; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HttpContext; import org.hamcrest.Description; import org.hamcrest.Matchers; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.api.Action; import org.jmock.api.Invocation; import org.limewire.core.settings.ConnectionSettings; import org.limewire.core.settings.FilterSettings; import org.limewire.core.settings.NetworkSettings; import org.limewire.core.settings.SharingSettings; import org.limewire.core.settings.UltrapeerSettings; import org.limewire.core.settings.UploadSettings; import org.limewire.http.httpclient.HttpClientUtils; import org.limewire.io.GUID; import org.limewire.util.TestUtils; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.Stage; import com.limegroup.gnutella.ActivityCallback; import com.limegroup.gnutella.HTTPAcceptor; import com.limegroup.gnutella.HTTPUploadManager; import com.limegroup.gnutella.LifecycleManager; import com.limegroup.gnutella.LimeTestUtils; import com.limegroup.gnutella.MessageRouter; import com.limegroup.gnutella.ReplyHandler; import com.limegroup.gnutella.Response; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.UploadManager; import com.limegroup.gnutella.altlocs.AltLocManager; import com.limegroup.gnutella.altlocs.AlternateLocation; import com.limegroup.gnutella.altlocs.AlternateLocationCollection; import com.limegroup.gnutella.altlocs.AlternateLocationFactory; import com.limegroup.gnutella.altlocs.DirectAltLoc; import com.limegroup.gnutella.altlocs.PushAltLoc; import com.limegroup.gnutella.auth.UrnValidator; import com.limegroup.gnutella.connection.ConnectionCapabilities; import com.limegroup.gnutella.connection.RoutedConnection; import com.limegroup.gnutella.filters.IPFilter; import com.limegroup.gnutella.http.ConstantHTTPHeaderValue; import com.limegroup.gnutella.http.HTTPConstants; import com.limegroup.gnutella.http.HTTPHeaderName; import com.limegroup.gnutella.library.FileDesc; import com.limegroup.gnutella.library.FileManager; import com.limegroup.gnutella.library.FileManagerTestUtils; import com.limegroup.gnutella.messages.MessageFactory; import com.limegroup.gnutella.messages.QueryReply; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.messages.Message.Network; import com.limegroup.gnutella.messages.vendor.HeadPing; import com.limegroup.gnutella.messages.vendor.HeadPong; import com.limegroup.gnutella.statistics.TcpBandwidthStatistics; import com.limegroup.gnutella.uploader.authentication.GnutellaBrowseFileListProvider; import com.limegroup.gnutella.uploader.authentication.GnutellaUploadFileListProvider; import com.limegroup.gnutella.util.LimeTestCase; public class AltLocUploadTest extends LimeTestCase { private static final int PORT = 6668; /** The file name, plain and encoded. */ private static final String testDirName = "com/limegroup/gnutella/uploader/data"; private static final String fileName = "alphabet test file#2.txt"; /** The hash of the file contents. */ private static final String baseHash = "GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ"; private static final String hash = "urn:sha1:" + baseHash; private static final String hashUrl = "http://localhost:" + PORT + "/uri-res/N2R?" + hash; /** * Features for push loc testing. */ private final static Header FALTFeatures = new BasicHeader( HTTPHeaderName.FEATURES.httpStringValue(), ConstantHTTPHeaderValue.PUSH_LOCS_FEATURE.httpStringValue()); private final static Header FWALTFeatures = new BasicHeader( HTTPHeaderName.FEATURES.httpStringValue(), ConstantHTTPHeaderValue.FWT_PUSH_LOCS_FEATURE.httpStringValue()); /** The filedesc of the shared file. */ private FileDesc fd; private HttpClient client; private TestUploadManager uploadManager; private AltLocManager altLocManager; private URN hashURN; private AlternateLocationFactory alternateLocationFactory; private Injector injector; private LifecycleManager lifecycleManager; public AltLocUploadTest(String name) { super(name); } public static Test suite() { return buildTestSuite(AltLocUploadTest.class); } public static void main(String args[]) { junit.textui.TestRunner.run(suite()); } @Override protected void setUp() throws Exception { hashURN = URN.createSHA1Urn(hash); doSettings(); // initialize services injector = LimeTestUtils.createInjector(Stage.PRODUCTION, new AbstractModule() { @Override protected void configure() { bind(UploadManager.class).to(TestUploadManager.class); bind(HTTPUploadSessionManager.class).to(TestUploadManager.class); } }); lifecycleManager = injector.getInstance(LifecycleManager.class); lifecycleManager.start(); uploadManager = (TestUploadManager) injector.getInstance(UploadManager.class); FileManager fileManager = injector.getInstance(FileManager.class); FileManagerTestUtils.waitForLoad(fileManager, 2000); File testDir = TestUtils.getResourceFile(testDirName); assertTrue("test directory could not be found", testDir.isDirectory()); File testFile = new File(testDir, fileName); Future<FileDesc> f1 = fileManager.getGnutellaFileList().add(testFile); fd = f1.get(1, TimeUnit.SECONDS); assertNotNull(fd); altLocManager = injector.getInstance(AltLocManager.class); alternateLocationFactory = injector.getInstance(AlternateLocationFactory.class); client = new DefaultHttpClient(); } @Override protected void tearDown() throws Exception { lifecycleManager.shutdown(); Thread.sleep(1000); } private void doSettings() throws UnknownHostException { SharingSettings.ADD_ALTERNATE_FOR_SELF.setValue(false); FilterSettings.BLACK_LISTED_IP_ADDRESSES .setValue(new String[] { "*.*.*.*" }); FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(new String[] { "127.*.*.*", InetAddress.getLocalHost().getHostAddress() }); NetworkSettings.PORT.setValue(PORT); UploadSettings.HARD_MAX_UPLOADS.setValue(10); UploadSettings.UPLOADS_PER_PERSON.setValue(10); UploadSettings.MAX_PUSHES_PER_HOST.setValue(9999); UploadSettings.CHECK_DUPES.setValue(false); // required so bias doesn't destroy tests UploadSettings.EXPIRE_LEGACY.setValue(false); FilterSettings.FILTER_DUPLICATES.setValue(false); ConnectionSettings.NUM_CONNECTIONS.setValue(8); ConnectionSettings.CONNECT_ON_STARTUP.setValue(true); ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false); ConnectionSettings.EVER_ACCEPTED_INCOMING.setValue(true); UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true); UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(true); } public void testFALTNotRequested() throws Exception { URN sha1 = URN.createSHA1Urn(hash); GUID clientGUID = new GUID(GUID.makeGuid()); GUID clientGUID2 = new GUID(GUID.makeGuid()); AlternateLocation direct = alternateLocationFactory.create("1.2.3.4:5", sha1); AlternateLocation push = alternateLocationFactory.create(clientGUID .toHexString() + ";1.2.3.4:5", sha1); ((PushAltLoc) push).updateProxies(true); PushAltLoc pushFwt = (PushAltLoc) alternateLocationFactory.create(clientGUID2 .toHexString() + ";5555:129.168.9.5;fwt/1.0;1.2.3.4:6", sha1); pushFwt.updateProxies(true); altLocManager.add(direct, null); altLocManager.add(push, null); altLocManager.add(pushFwt, null); assertEquals(0, ((PushAltLoc) push).supportsFWTVersion()); assertEquals(1, pushFwt.supportsFWTVersion()); assertEquals(3, altLocManager.getNumLocs( fd.getSHA1Urn())); HttpGet method = new HttpGet(hashUrl); method.addHeader("X-Alt", ""); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNull(response.getFirstHeader("X-Falt")); } finally { HttpClientUtils.releaseConnection(response); } assertEquals(1, uploadManager.activeUploads.size()); HTTPUploader uploader = uploadManager.activeUploads.get(0); assertFalse(uploader.getAltLocTracker().wantsFAlts()); assertEquals(0, uploader.getAltLocTracker().getFwtVersion()); } public void testFALTWhenRequested() throws Exception { URN sha1 = URN.createSHA1Urn(hash); GUID clientGUID = new GUID(GUID.makeGuid()); GUID clientGUID2 = new GUID(GUID.makeGuid()); AlternateLocation direct = alternateLocationFactory.create("1.2.3.4:5", sha1); final AlternateLocation push = alternateLocationFactory.create(clientGUID .toHexString() + ";1.2.3.4:5", sha1); ((PushAltLoc) push).updateProxies(true); final PushAltLoc pushFwt = (PushAltLoc) alternateLocationFactory.create( clientGUID2.toHexString() + ";5555:129.168.9.5;fwt/1.0;1.2.3.4:6", sha1); pushFwt.updateProxies(true); altLocManager.add(direct, null); altLocManager.add(push, null); altLocManager.add(pushFwt, null); assertEquals(0, ((PushAltLoc) push).supportsFWTVersion()); assertEquals(1, pushFwt.supportsFWTVersion()); assertEquals(3, altLocManager.getNumLocs( fd.getSHA1Urn())); HttpGet method = new HttpGet(hashUrl); method.addHeader(FALTFeatures); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-FAlt")); String value = response.getFirstHeader("X-FAlt").getValue(); assertEquals((push.httpStringValue() + "," + pushFwt.httpStringValue()).length(), value.length()); assertTrue(value.contains(push.httpStringValue())); assertTrue(value.contains(pushFwt.httpStringValue())); } finally { HttpClientUtils.releaseConnection(response); } assertEquals(1, uploadManager.activeUploads.size()); HTTPUploader uploader = uploadManager.activeUploads.get(0); assertTrue(uploader.getAltLocTracker().wantsFAlts()); assertEquals(0, uploader.getAltLocTracker().getFwtVersion()); } public void testFWALTWhenRequested() throws Exception { URN sha1 = URN.createSHA1Urn(hash); GUID clientGUID = new GUID(GUID.makeGuid()); GUID clientGUID2 = new GUID(GUID.makeGuid()); AlternateLocation direct = alternateLocationFactory.create("1.2.3.4:5", sha1); final AlternateLocation push = alternateLocationFactory.create(clientGUID .toHexString() + ";1.2.3.4:5", sha1); ((PushAltLoc) push).updateProxies(true); final PushAltLoc pushFwt = (PushAltLoc) alternateLocationFactory.create( clientGUID2.toHexString() + ";5555:129.168.9.5;fwt/1.0;1.2.3.4:6", sha1); pushFwt.updateProxies(true); altLocManager.add(direct, null); altLocManager.add(push, null); altLocManager.add(pushFwt, null); assertEquals(0, ((PushAltLoc) push).supportsFWTVersion()); assertEquals(1, pushFwt.supportsFWTVersion()); assertEquals(3, altLocManager.getNumLocs( fd.getSHA1Urn())); HttpGet method = new HttpGet(hashUrl); method.addHeader(FWALTFeatures); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-FAlt")); String value = response.getFirstHeader("X-FAlt").getValue(); assertEquals(pushFwt.httpStringValue(), value); } finally { HttpClientUtils.releaseConnection(response); } assertEquals(1, uploadManager.activeUploads.size()); HTTPUploader uploader = uploadManager.activeUploads.get(0); assertTrue(uploader.getAltLocTracker().wantsFAlts()); assertEquals((int) HTTPConstants.FWT_TRANSFER_VERSION, uploader .getAltLocTracker().getFwtVersion()); } public void testUploaderStoresAllAlts() throws Exception { URN sha1 = URN.createSHA1Urn(hash); GUID clientGUID = new GUID(GUID.makeGuid()); AlternateLocation direct = alternateLocationFactory.create("1.2.3.4:5", sha1); AlternateLocation push = alternateLocationFactory.create(clientGUID .toHexString() + ";1.2.3.4:5", sha1); ((PushAltLoc) push).updateProxies(true); assertEquals(0, altLocManager.getNumLocs( fd.getSHA1Urn())); HttpGet method = new HttpGet(hashUrl); method.addHeader("X-Alt", direct.httpStringValue()); method.addHeader("X-FAlt", push.httpStringValue()); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); } finally { HttpClientUtils.releaseConnection(response); } assertEquals(2, altLocManager.getNumLocs( fd.getSHA1Urn())); assertEquals(1, altLocManager.getPushNoFWT( fd.getSHA1Urn()).getAltLocsSize()); assertEquals(1, altLocManager.getDirect( fd.getSHA1Urn()).getAltLocsSize()); assertTrue(altLocManager.getPushNoFWT(fd.getSHA1Urn()) .contains(push)); assertTrue(altLocManager.getDirect(fd.getSHA1Urn()) .contains(direct)); } public void testAlternateLocationAddAndRemove() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // ensure that one removal doesn't stop it. altLocManager.remove(al, null); method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // add a second one, so we can check to make sure // another removal removes the first one. AlternateLocation al2 = alternateLocationFactory.create("2.2.2.2:2", hashURN); altLocManager.add(al2, null); method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals(value, "2.2.2.2:2,1.1.1.1:1".length(), value.length()); assertTrue(value.contains("1.1.1.1:1")); assertTrue(value.contains("2.2.2.2:2")); } finally { HttpClientUtils.releaseConnection(response); } // remove the first guy again, should only have loc2 left. altLocManager.remove(al, null); method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("2.2.2.2:2", value); } finally { HttpClientUtils.releaseConnection(response); } } public void testSentHeaderIsUsed() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // add a header that gives a new location. AlternateLocation sendAl = alternateLocationFactory.create("2.2.2.2:2", hashURN); method = new HttpGet(hashUrl); method.addHeader("X-Alt", sendAl.httpStringValue()); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // make sure the FD has that loc now. AlternateLocationCollection<DirectAltLoc> alc = altLocManager .getDirect(fd.getSHA1Urn()); assertEquals("unexpected number of locs", 2, alc.getAltLocsSize()); List<DirectAltLoc> alts = new LinkedList<DirectAltLoc>(); for (DirectAltLoc anAlc : alc) { alts.add(anAlc); } assertTrue(alts.contains(al)); assertTrue(alts.contains(sendAl)); // make sure a request will give us both locs now. method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("2.2.2.2:2,1.1.1.1:1".length(), value.length()); assertTrue(value.contains("1.1.1.1:1")); assertTrue(value.contains("2.2.2.2:2")); } finally { HttpClientUtils.releaseConnection(response); } // demote the location (don't remove) method = new HttpGet(hashUrl); method.addHeader("X-NAlt", sendAl.httpStringValue()); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // should still have it. assertEquals("unexpected number of locs", 2, alc.getAltLocsSize()); alts = new LinkedList<DirectAltLoc>(); for (DirectAltLoc anAlc : alc) alts.add(anAlc); assertTrue(alts.contains(al)); assertTrue(alts.contains(sendAl)); // now remove method = new HttpGet(hashUrl); method.addHeader("X-NAlt", sendAl.httpStringValue()); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } assertEquals("unexpected number of locs", 1, alc.getAltLocsSize()); assertEquals(al, alc.iterator().next()); } public void testMiniNewHeaderIsUsed() throws Exception { // Add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // now try a header without a port, should be 6346. AlternateLocation sendAl = alternateLocationFactory.create("2.3.4.5:6346", hashURN); method = new HttpGet(hashUrl); method.addHeader("X-Alt", "2.3.4.5"); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // nake sure the FD has that loc now. AlternateLocationCollection<DirectAltLoc> alc = altLocManager .getDirect(fd.getSHA1Urn()); assertEquals("wrong # locs", 2, alc.getAltLocsSize()); List<DirectAltLoc> alts = new LinkedList<DirectAltLoc>(); for (DirectAltLoc anAlc : alc) { alts.add(anAlc); } assertTrue(alts.contains(al)); assertTrue(alts.contains(sendAl)); } /** * Tests that headers with multiple values in them are * read correctly */ public void testMultipleAlternates() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // add a header that gives a new location. AlternateLocation al1 = alternateLocationFactory.create("1.2.3.1:1", hashURN); AlternateLocation al2 = alternateLocationFactory.create("1.2.3.2:2", hashURN); AlternateLocation al3 = alternateLocationFactory.create("1.2.3.4:6346", hashURN); method = new HttpGet(hashUrl); method.addHeader("X-Alt", al1.httpStringValue() + ", " + al2.httpStringValue() + ", " + al3.httpStringValue()); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // make sure the FD has that loc now. AlternateLocationCollection<DirectAltLoc> alc = altLocManager .getDirect(fd.getSHA1Urn()); assertEquals("wrong # locs", 4, alc.getAltLocsSize()); List<DirectAltLoc> alts = new LinkedList<DirectAltLoc>(); for (DirectAltLoc anAlc : alc) { alts.add(anAlc); } assertTrue(alts.contains(al)); assertTrue(alts.contains(al1)); assertTrue(alts.contains(al2)); assertTrue(alts.contains(al3)); // demote method = new HttpGet(hashUrl); method.addHeader("X-NAlt", "1.2.3.1:1, " + al2.httpStringValue() + ", " + al3.httpStringValue()); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); } finally { HttpClientUtils.releaseConnection(response); } // should still have it assertEquals("wrong # locs", 4, alc.getAltLocsSize()); // remove method = new HttpGet(hashUrl); method.addHeader("X-NAlt", al1.httpStringValue() + ", 1.2.3.2:2, " + al3.httpStringValue()); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); } finally { HttpClientUtils.releaseConnection(response); } assertEquals("wrong # locs", 1, alc.getAltLocsSize()); assertEquals(al, alc.iterator().next()); } /** * Tests that when reading the NFAlt header we only remove proxies. */ public void testRemovingNFAlt() throws Exception { GUID g = new GUID(GUID.makeGuid()); URN urn = URN.createSHA1Urn(hash); PushAltLoc abc = (PushAltLoc) alternateLocationFactory.create(g.toHexString() + ";1.1.1.1:1;2.2.2.2:2;3.3.3.3:3", urn); String abcHttp = abc.httpStringValue(); PushAltLoc bcd = (PushAltLoc) alternateLocationFactory.create(g.toHexString() + ";2.2.2.2:2;3.3.3.3:3;4.4.4.4:4", urn); bcd.updateProxies(true); String bcdHttp = bcd.httpStringValue(); altLocManager.add(bcd, null); assertEquals(1, altLocManager.getNumLocs(urn)); HttpGet method = new HttpGet(hashUrl); method.addHeader("X-NFAlt", abcHttp); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); } finally { HttpClientUtils.releaseConnection(response); } // two of the proxies of bcd should be gone assertEquals("wrong # locs", 1, altLocManager .getPushNoFWT(fd.getSHA1Urn()).getAltLocsSize()); assertEquals("wrong # proxies", 1, bcd.getPushAddress().getProxies() .size()); // now repeat, sending all three original proxies of bce as NFAlts //Thread.sleep(1000); method = new HttpGet(hashUrl); method.addHeader("X-NFAlt", bcdHttp); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); } finally { HttpClientUtils.releaseConnection(response); } // all proxies should be gone, and bcd should be removed from // the filedesc assertEquals("wrong # locs", 0, altLocManager .getPushNoFWT(fd.getSHA1Urn()).getAltLocsSize()); assertEquals("wrong # proxies", 0, bcd.getPushAddress().getProxies() .size()); } // unfortunately we can't test with private addresses // because all these connections require that local_is_private // is false, which turns off isPrivateAddress checking. public void testInvalidAltsAreIgnored() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // add an invalid alt String invalidAddr = "http://0.0.0.0:6346/uri-res/N2R?" + hash; method = new HttpGet(hashUrl); method.addHeader("X-Alt", invalidAddr); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // FD should still only have 1 AlternateLocationCollection alc = altLocManager .getDirect(fd.getSHA1Urn()); assertEquals("wrong # locs: " + alc, 1, alc.getAltLocsSize()); assertEquals(al, alc.iterator().next()); invalidAddr = "http://255.255.255.255:6346/uri-res/N2R?" + hash; method = new HttpGet(hashUrl); method.addHeader("X-Alt", invalidAddr); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // FD should still only have 1 assertEquals("wrong # locs: " + alc, 1, alc.getAltLocsSize()); assertEquals(al, alc.iterator().next()); // add an invalid port String invalidPort = "http://1.2.3.4:0/uri-res/N2R?" + hash; method = new HttpGet(hashUrl); method.addHeader("X-Alt", invalidPort); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // FD should still only have 1 assertEquals("wrong # locs: " + alc, 1, alc.getAltLocsSize()); assertEquals(al, alc.iterator().next()); invalidPort = "http://1.2.3.4:-2/uri-res/N2R?" + hash; method = new HttpGet(hashUrl); method.addHeader("X-Alt", invalidPort); method.addHeader("Connection", "close"); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // FD should still only have 1 assertEquals("wrong # locs: " + alc, 1, alc.getAltLocsSize()); assertEquals(al, alc.iterator().next()); } public void test10AltsAreSent() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); HttpProtocolParams.setVersion(client.getParams(), HttpVersion.HTTP_1_0); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } for (int i = 0; i < 20; i++) { altLocManager.add(alternateLocationFactory.create("1.1.1." + i + ":6346", hashURN), null); } assertEquals(21, altLocManager.getDirect( fd.getSHA1Urn()).getAltLocsSize()); String pre = "1.1.1."; ArrayList<String> required = new ArrayList<String>(); for (int i = 0; i < 20; i++) { required.add(pre + i); } method = new HttpGet(hashUrl); try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); // Find only 10 of the items, but not less than 10 & not more than 10. assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10); } finally { HttpClientUtils.releaseConnection(response); } } private List<String> assertHeaderEquals(ArrayList<String> required, String value, int amountNeeded) { String[] valueList = value.replace(" ", "").split(","); assertGreaterThan(0, required.size()); List<String> actual = new ArrayList<String>(Arrays.asList(valueList)); if(amountNeeded > 0) { assertGreaterThanOrEquals("must give some requirements!", amountNeeded, required.size()); assertEquals(amountNeeded, actual.size()); } else { assertEquals(required.size(), actual.size()); } List<String> missing = new ArrayList<String>(); List<String> found = new ArrayList<String>(); for(String oneValue : required) { if(!actual.contains(oneValue)) { missing.add(oneValue); } else { actual.remove(oneValue); found.add(oneValue); } } assertTrue("wanted: " + amountNeeded + " of: " + required + ", found only: " + found + ", remaining: " + actual, actual.isEmpty()); if(amountNeeded < 0) { assertEmpty(missing); } return found; } public void testAltsExpire() throws Exception { UploadSettings.EXPIRE_LEGACY.setValue(true); UploadSettings.LEGACY_EXPIRATION_DAMPER.setValue((float) Math.E - 0.2f); // test that an altloc will expire if given out too often AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); assertTrue(al.canBeSent(AlternateLocation.MESH_LEGACY)); altLocManager.add(al, null); // send it out several times int i = 0; try { for (i = 0; i < 10; i++) { HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } } fail("altloc didn't expire"); } catch (AssertionFailedError expected) { } assertLessThan(10, i); assertFalse(al.canBeSent(AlternateLocation.MESH_LEGACY)); // now add the altloc again, it will be reset altLocManager.add(al, null); assertTrue(al.canBeSent(AlternateLocation.MESH_LEGACY)); } /** * tests that when an altloc has expired from all the meshes it is removed. */ public void testExpiredAltsRemoved() throws Exception { FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(new String[] { "*.*.*.*" }); injector.getInstance(IPFilter.class).refreshHosts(); // set the expiration values to the bare minimum UploadSettings.EXPIRE_LEGACY.setValue(true); UploadSettings.LEGACY_BIAS.setValue(0f); UploadSettings.PING_BIAS.setValue(0f); UploadSettings.RESPONSE_BIAS.setValue(0f); // create an altloc AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); assertTrue(al.canBeSent(AlternateLocation.MESH_LEGACY)); assertTrue(al.canBeSent(AlternateLocation.MESH_PING)); assertTrue(al.canBeSent(AlternateLocation.MESH_RESPONSE)); altLocManager.add(al, null); // drain the meshes in various orders drainLegacy(); drainPing(); drainResponse(); assertFalse(altLocManager .hasAltlocs(al.getSHA1Urn())); // and re-add the altloc al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); // repeat drainResponse(); drainLegacy(); drainPing(); assertFalse(altLocManager .hasAltlocs(al.getSHA1Urn())); al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); // repeat 2 drainPing(); drainResponse(); drainLegacy(); assertFalse(altLocManager .hasAltlocs(al.getSHA1Urn())); } private void drainLegacy() throws Exception { int i = 0; try { for (; i < 20; i++) { HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } } fail("altloc didn't expire"); } catch (AssertionFailedError expected) { } assertGreaterThan(1, i); assertLessThan(20, i); } private void drainPing() throws Exception { MessageFactory messageFactory = injector.getInstance(MessageFactory.class); HeadPing ping = new HeadPing(new GUID(GUID.makeGuid()), fd.getSHA1Urn(), HeadPing.ALT_LOCS); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ping.write(baos); byte[] data = baos.toByteArray(); DatagramPacket toSend = new DatagramPacket(data, data.length, new InetSocketAddress(InetAddress.getLocalHost(), PORT)); int i = 0; for (; i < 20; i++) { DatagramSocket sock = null; try { sock = new DatagramSocket(10000 + i); sock.setSoTimeout(2000); sock.send(toSend); byte[] recv = new byte[5000]; DatagramPacket rcv = new DatagramPacket(recv, recv.length); sock.receive(rcv); ByteArrayInputStream bais = new ByteArrayInputStream(recv, 0, rcv.getLength()); HeadPong pong = (HeadPong) messageFactory.read(bais, Network.TCP); if (pong.getAltLocs().isEmpty()) break; } catch (IOException iox) { fail("didn't get response "+i,iox); } finally { if (sock != null) sock.close(); } } assertGreaterThan(1, i); assertLessThan(20, i); } private void drainResponse() throws Exception { MessageFactory messageFactory = injector.getInstance(MessageFactory.class); MessageRouter messageRouter = injector.getInstance(MessageRouter.class); FilterSettings.FILTER_HASH_QUERIES.setValue(false); // easier with hash Mockery mockery = new Mockery(); final RoutedConnection handler = mockery.mock(RoutedConnection.class); final ConnectionCapabilities capabilities = mockery.mock(ConnectionCapabilities.class); assertTrue(altLocManager.hasAltlocs(fd.getSHA1Urn())); int i = 0; for (; i < 20; i++) { final int iteration = i; // just for documentation final QueryRequest request = mockery.mock(QueryRequest.class); final Set<URN> urns = new HashSet<URN>(); urns.add(fd.getSHA1Urn()); final AtomicReference<QueryReply> replyRef = new AtomicReference<QueryReply>(null); final Action checkAlts = new Action() { public void describeTo(Description description) { description.appendText("checks if query reply has altlocs at iteration "+iteration); } public Object invoke(Invocation invocation) throws Throwable { QueryReply reply = (QueryReply) invocation.getParameter(0); replyRef.set(reply); return null; } }; mockery.checking(new Expectations(){{ one(handler).handleQueryReply(with(Matchers.notNullValue(QueryReply.class)), with(Matchers.nullValue(ReplyHandler.class))); will(checkAlts); // various stubbed out methods allowing(handler).isOpen(); will(returnValue(true)); allowing(handler).getConnectionCapabilities(); will(returnValue(capabilities)); allowing(handler).isSupernodeClientConnection(); will(returnValue(false)); allowing(handler).isGoodUltrapeer(); will(returnValue(false)); // some request-specific conditions one(request).hop(); atLeast(1).of(request).getQueryUrns(); will(returnValue(urns)); atLeast(1).of(request).getHandlerClass(); will(returnValue(QueryRequest.class)); atLeast(1).of(request).getQuery(); will(returnValue("")); atLeast(1).of(request).getGUID(); // its important that the guid be different will(returnValue((new GUID()).bytes())); // every iteration atLeast(1).of(request).desiresAll(); will(returnValue(true)); allowing(request).getNetwork(); will(returnValue(Network.TCP)); allowing(handler).isPersonalSpam(request); will(returnValue(false)); allowing(handler).getAddress(); will(returnValue(null)); allowing(handler).getPort(); will(returnValue(-1)); ignoring(request).shouldIncludeXMLInResponse(); ignoring(request).getTotalLength(); ignoring(request).isFirewalledSource(); ignoring(request).canDoFirewalledTransfer(); ignoring(request).desiresOutOfBandReplies(); ignoring(request).isWhatIsNewRequest(); ignoring(request).getTTL(); ignoring(request).getHops(); ignoring(request).getRichQuery(); ignoring(request).isQueryForLW(); ignoring(request).getFeatureSelector(); ignoring(request).isFeatureQuery(); ignoring(request).desiresXMLResponses(); ignoring(request).isMulticast(); ignoring(request).getLength(); ignoring(request).desiresPartialResults(); }}); messageRouter.handleMessage(request, handler); mockery.assertIsSatisfied(); QueryReply replied = replyRef.get(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); replied.write(baos); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); QueryReply reply = (QueryReply) messageFactory.read(bais, Network.TCP); Response resp = reply.getResultsArray()[0]; if (resp.getLocations().isEmpty()) break; } assertGreaterThan(1, i); assertLessThan(20, i); FilterSettings.FILTER_HASH_QUERIES.revertToDefault(); } public void testChunksGiveDifferentLocs() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); // method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } for (int i = 0; i < 20; i++) { altLocManager.add( alternateLocationFactory.create("1.1.1." + i + ":6346", hashURN), null); } assertEquals(21, altLocManager.getNumLocs( fd.getSHA1Urn())); String pre = "1.1.1."; List<String> found = new ArrayList<String>(); found.add("1.1.1.1:1"); ArrayList<String> required = new ArrayList<String>(); for (int i = 0; i < 20; i++) { required.add(pre + i); } // Find everything (up to 10 more) except the initial 1.1.1.1:1 method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=0-1"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); found.addAll(assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10)); } finally { HttpClientUtils.releaseConnection(response); } required = new ArrayList<String>(); for (int i = 0; i < 20; i++) { required.add(pre + i); } required.removeAll(found); // Find everything except the first batch & 1.1.1.1:1 method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=2-3"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); found.addAll(assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10)); } finally { HttpClientUtils.releaseConnection(response); } required = new ArrayList<String>(); for (int i = 0; i < 20; i++) { required.add(pre + i); } required.removeAll(found); // Nothing left to find! assertEquals(0, required.size()); method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=4-5"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNull(response.getFirstHeader("X-Alt")); } finally { HttpClientUtils.releaseConnection(response); } // Now if some more are added to file desc, make sure they're reported. altLocManager.add(alternateLocationFactory.create("1.1.1.99:6346", hashURN), null); // Find only the additional 1.1.1.99 method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=6-7"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.99", value); } finally { HttpClientUtils.releaseConnection(response); } } public void testPrioritizingAlternates() throws Exception { // add a simple marker alt so we know it only contains that AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); altLocManager.add(al, null); HttpGet method = new HttpGet(hashUrl); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } // get rid of it. altLocManager.remove(al, null); altLocManager.remove(al, null); for (int i = 0; i < 50; i++) { al = alternateLocationFactory.create("1.1.1." + i + ":6346", hashURN); altLocManager.add(al, null); // 0-9, make as demoted. if (i < 10) { altLocManager.remove(al, null); // should // demote. } // 10-19, increment once. else if (i < 20) { altLocManager.add(al, null); // should // increment. } // 20-29, increment & demote. else if (i < 30) { altLocManager.add(al, null); // increment altLocManager.remove(al, null); // demote } // 30-39, increment twice. else if (i < 40) { altLocManager.add(al, null); // increment altLocManager.add(al, null); // increment } // 40-49, leave normal. } AlternateLocationCollection alc = altLocManager .getDirect(fd.getSHA1Urn()); assertEquals(50, alc.getAltLocsSize()); // Order of return should be: // 40-49 returned first // 10-19 returned next // 30-39 returned next // 0-9 returned next // 20-29 returned next String pre = "1.1.1."; ArrayList<String> required = new ArrayList<String>(); for (int i = 0; i < 10; i++) { required.add(pre + (40 + i)); } method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=0-1"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10); } finally { HttpClientUtils.releaseConnection(response); } required = new ArrayList<String>(); for (int i = 0; i < 10; i++) { required.add(pre + (10 + i)); } method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=2-3"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10); } finally { HttpClientUtils.releaseConnection(response); } required = new ArrayList<String>(); for (int i = 0; i < 10; i++) { required.add(pre + (30 + i)); } method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=4-5"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10); } finally { HttpClientUtils.releaseConnection(response); } required = new ArrayList<String>(); for (int i = 0; i < 10; i++) { required.add(pre + i); } method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=6-7"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10); } finally { HttpClientUtils.releaseConnection(response); } required = new ArrayList<String>(); for (int i = 0; i < 10; i++) { required.add(pre + (20 + i)); } method = new HttpGet(hashUrl); method.addHeader("Range", "bytes=8-9"); try { response = client.execute(method); assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); assertHeaderEquals(required, response.getFirstHeader("X-Alt").getValue(), 10); } finally { HttpClientUtils.releaseConnection(response); } } public void testAltsDontExpire() throws Exception { UploadSettings.EXPIRE_LEGACY.setValue(true); UploadSettings.LEGACY_EXPIRATION_DAMPER.setValue((float) Math.E / 4); // test that an altloc will not expire if given out less often AlternateLocation al = alternateLocationFactory.create("1.1.1.1:1", hashURN); assertTrue(al.canBeSent(AlternateLocation.MESH_LEGACY)); altLocManager.add(al, null); for (int i = 0; i < 10; i++) { HttpGet method = new HttpGet(hashUrl); method.addHeader("Connection", "close"); HttpResponse response = null; try { response = client.execute(method); assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getFirstHeader("X-Alt")); String value = response.getFirstHeader("X-Alt").getValue(); assertEquals("1.1.1.1:1", value); } finally { HttpClientUtils.releaseConnection(response); } Thread.sleep(8 * 1000); } assertTrue(al.canBeSent(AlternateLocation.MESH_LEGACY)); } /** * testFALTNotRequested(), testFALTWhenRequested() and * testFWALTWhenRequested() fail if the server processes the entire request * before we start reading from the InputStreams. That means: our * HTTPUploader is added to UploadManagers private _activeUploadsList, the * request is processed and the HTTPUploader is removed from the List. We * start reading from the InputStream and the assertions in the mentioned * tests fail because our HTTPUploader is no longer in that List. So, we * have to cache the HTTPUploader somehow what this extension does. */ @Singleton private static class TestUploadManager extends HTTPUploadManager { private List<HTTPUploader> activeUploads = new ArrayList<HTTPUploader>(); @Inject TestUploadManager(UploadSlotManager slotManager, HttpRequestHandlerFactory httpRequestHandlerFactory, Provider<HTTPAcceptor> httpAcceptor, Provider<FileManager> fileManager, Provider<ActivityCallback> activityCallback, TcpBandwidthStatistics tcpBandwidthStatistics, Provider<GnutellaUploadFileListProvider> gnutellaUploadFileListProvider, Provider<GnutellaBrowseFileListProvider> gnutellaBrowseFileListProvider, UrnValidator urnValidator) { super(slotManager, httpRequestHandlerFactory, httpAcceptor, fileManager, activityCallback, tcpBandwidthStatistics, gnutellaUploadFileListProvider, gnutellaBrowseFileListProvider, urnValidator); } @Override public synchronized void addAcceptedUploader(HTTPUploader uploader, HttpContext context) { activeUploads.add(uploader); super.addAcceptedUploader(uploader, context); } public void clearUploads() { cleanup(); activeUploads.clear(); } } }