package org.limewire.core.impl.integration;
import java.io.File;
import java.net.URI;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.util.EntityUtils;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.api.Invocation;
import org.jmock.lib.action.CustomAction;
import org.limewire.core.impl.tests.CoreGlueTestUtils;
import org.limewire.gnutella.tests.LimeTestCase;
import org.limewire.gnutella.tests.LimeTestUtils;
import org.limewire.http.auth.Authenticator;
import org.limewire.http.auth.AuthenticatorRegistry;
import org.limewire.http.httpclient.HttpClientUtils;
import org.limewire.http.httpclient.LimeHttpClient;
import org.limewire.io.LocalSocketAddressProvider;
import org.limewire.io.LocalSocketAddressProviderStub;
import org.limewire.util.PrivilegedAccessor;
import org.limewire.util.TestUtils;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.limegroup.gnutella.Acceptor;
import com.limegroup.gnutella.LifecycleManager;
import com.limegroup.gnutella.RequestCache;
import com.limegroup.gnutella.library.FileCollectionManager;
import com.limegroup.gnutella.library.FileDesc;
import com.limegroup.gnutella.library.FileManagerTestUtils;
import com.limegroup.gnutella.library.Library;
import com.limegroup.gnutella.library.SharedFileCollection;
/**
* Collection of friend upload integration tests.
*/
public class FriendUploadTest extends LimeTestCase {
private static final String FILE_NAME = "alphabet test file#2.txt";
private static final String FRIEND_ID = "me@you.com";
@Inject private Injector injector;
@Inject private Acceptor acceptor;
private int port;
@Inject private FileCollectionManager fileManager;
private String relativeFileNameUrl;
@Inject private LimeHttpClient client;
@Inject private Library library;
private FileDesc fileDesc;
private Mockery context;
public FriendUploadTest(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
context = new Mockery();
CoreGlueTestUtils.createInjectorAndStart(TestUtils.bind(LocalSocketAddressProvider.class).to(LocalSocketAddressProviderStub.class), LimeTestUtils.createModule(this));
port = acceptor.getPort(false);
FileManagerTestUtils.waitForLoad(library, 4 * 1000);
loadFiles();
}
private void loadFiles() throws Exception {
SharedFileCollection friendFileList = fileManager.createNewCollection("test collection");
friendFileList.addFriend(FRIEND_ID);
File testFile = TestUtils.getResourceInPackage(FILE_NAME, getClass());
fileDesc = friendFileList.add(testFile).get();
relativeFileNameUrl = LimeTestUtils.getRelativeRequest(fileDesc.getSHA1Urn());
}
@Override
protected void tearDown() throws Exception {
injector.getInstance(LifecycleManager.class).shutdown();
}
/**
* Ensures unauthenticated download request fails and requestor receives basic
* authentication challenge and connection stays open.
* Then ensures that authenticated request goes through.
*/
public void testUnauthenticatedFriendDownloadGetsChallengeResponse() throws Exception {
HttpGet method = new HttpGet("http://localhost:" + port+ "/friend/download/me%40you.com" + relativeFileNameUrl);
HttpResponse response = null;
try {
response = client.execute(method);
assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
assertEquals("Basic realm=\"secure\"", response.getFirstHeader("WWW-Authenticate").getValue());
} finally {
HttpClientUtils.releaseConnection(response);
}
assertConnectionIsOpen(true, method);
// see if everything works if authentication is sent correctly
testAuthenticatedFriendGetRequestIsOKed();
}
/**
* Ensures that an authenticated request without challenge/response is OKed immediately
*/
public void testAuthenticatedFriendGetRequestIsOKed() throws Exception {
registerAuthenticator(true);
HttpGet method = new HttpGet("http://localhost:" + port+ "/friend/download/me%40you.com" + relativeFileNameUrl);
// add authentication header
// auth data: me@you.com:hello
method.addHeader("Authorization", " Basic bWVAeW91LmNvbTpoZWxsbw==");
HttpResponse response = null;
try {
response = client.execute(method);
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
String contents = EntityUtils.toString(response.getEntity());
assertEquals("abcdefghijklmnopqrstuvwxyz", contents);
} finally {
HttpClientUtils.releaseConnection(response);
}
assertConnectionIsOpen(true, method);
context.assertIsSatisfied();
}
public void testWrongAuthenticationIsRejectedAsUnauthorized() throws Exception {
registerAuthenticator(false);
HttpGet method = new HttpGet("http://localhost:" + port+ "/friend/download/me%40you.com" + relativeFileNameUrl);
// add authentication header
// auth data: me@you.com:hello
method.addHeader("Authorization", " Basic bWVAeW91LmNvbTpoZWxsbw==");
HttpResponse response = null;
try {
response = client.execute(method);
assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
} finally {
HttpClientUtils.releaseConnection(response);
}
assertConnectionIsOpen(true, method);
context.assertIsSatisfied();
}
public void testAuthenticatedRangeHeadDownload() throws Exception {
registerAuthenticator(true);
HttpHead method = new HttpHead("http://localhost:" + port+ "/friend/download/me%40you.com" + relativeFileNameUrl);
// add authentication header
// auth data: me@you.com:hello
method.addHeader("Authorization", " Basic bWVAeW91LmNvbTpoZWxsbw==");
method.addHeader("Range", "bytes 2-5");
HttpResponse response = null;
try {
response = client.execute(method);
assertEquals(HttpStatus.SC_PARTIAL_CONTENT, response.getStatusLine().getStatusCode());
assertNotNull(response.getFirstHeader("Content-range"));
assertEquals("bytes 2-5/26", response.getFirstHeader(
"Content-range").getValue());
assertNull(response.getEntity());
} finally {
HttpClientUtils.releaseConnection(response);
}
assertConnectionIsOpen(true, method);
context.assertIsSatisfied();
}
public void testConnectionCloseHeaderIsHonoredAuthenticated() throws Exception {
testConnectionCloseHeaderIsHonored(true, HttpStatus.SC_OK);
}
public void testConnectionCloseHeaderIsHonoredUnAuthenticated() throws Exception {
testConnectionCloseHeaderIsHonored(false, HttpStatus.SC_UNAUTHORIZED);
}
public void testConnectionCloseHeaderIsHonored(boolean authenticate, int code) throws Exception {
registerAuthenticator(authenticate);
HttpGet method = new HttpGet("http://localhost:" + port+ "/friend/download/me%40you.com" + relativeFileNameUrl);
// add authentication header
// auth data: me@you.com:hello
method.addHeader("Authorization", " Basic bWVAeW91LmNvbTpoZWxsbw==");
method.addHeader("Connection", "close");
HttpResponse response = null;
try {
response = client.execute(method);
assertEquals(code, response.getStatusLine().getStatusCode());
} finally {
HttpClientUtils.releaseConnection(response);
}
assertConnectionIsOpen(false, method);
context.assertIsSatisfied();
}
public void testFriendRequestIsNeverBanned() throws Exception {
PrivilegedAccessor.setValue(RequestCache.class, "FIRST_CHECK_TIME",
new Long(10 * 1000));
registerAuthenticator(true);
HttpGet method = new HttpGet("http://localhost:" + port+ "/friend/download/me%40you.com" + relativeFileNameUrl);
// add authentication header
// auth data: me@you.com:hello
method.addHeader("Authorization", " Basic bWVAeW91LmNvbTpoZWxsbw==");
HttpResponse response = null;
try {
response = client.execute(method);
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
String contents = EntityUtils.toString(response.getEntity());
assertEquals("abcdefghijklmnopqrstuvwxyz", contents);
} finally {
HttpClientUtils.releaseConnection(response);
}
assertConnectionIsOpen(true, method);
context.assertIsSatisfied();
}
private void registerAuthenticator(final boolean authenticate) {
AuthenticatorRegistry registry = injector.getInstance(AuthenticatorRegistry.class);
final Authenticator authenticator = context.mock(Authenticator.class);
registry.register(authenticator);
context.checking(new Expectations() {{
one(authenticator).authenticate(with(any(UsernamePasswordCredentials.class)));
will(new CustomAction("check passowrd") {
@Override
public Object invoke(Invocation invocation) throws Throwable {
UsernamePasswordCredentials credentials = (UsernamePasswordCredentials)invocation.getParameter(0);
assertEquals("me@you.com", credentials.getUserName());
assertEquals("hello", credentials.getPassword());
return authenticate;
}
});
}});
}
private void assertConnectionIsOpen(boolean open, HttpUriRequest request) throws InterruptedException, ConnectionPoolTimeoutException {
URI uri = request.getURI();
HttpRoute route = new HttpRoute(new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()));
ManagedClientConnection connection = client.getConnectionManager().requestConnection(route, null).getConnection(0, null);
assertEquals(open, connection.isOpen());
client.getConnectionManager().releaseConnection(connection, -1, null);
}
}