package com.limegroup.gnutella.browser;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.nio.entity.ConsumingNHttpEntity;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.nio.entity.NFileEntity;
import org.apache.http.nio.protocol.SimpleNHttpRequestHandler;
import org.apache.http.protocol.HttpContext;
import org.limewire.concurrent.ExecutorsHelper;
import org.limewire.http.BasicHttpAcceptor;
import org.limewire.http.auth.AuthenticationInterceptor;
import org.limewire.core.api.library.LibraryManager;
import org.limewire.inject.EagerSingleton;
import com.google.inject.Inject;
import com.limegroup.gnutella.Constants;
import com.limegroup.gnutella.library.FileDesc;
import com.limegroup.gnutella.util.LimeWireUtils;
@EagerSingleton
public class LocalHTTPAcceptor extends BasicHttpAcceptor {
private static final Log LOG = LogFactory.getLog(LocalHTTPAcceptor.class);
private static final String[] SUPPORTED_METHODS = new String[] { "GET",
"HEAD", };
private final Executor magnetExecutor = ExecutorsHelper.newProcessingQueue("magnet-handler");
/** Magnet request for a default action on parameters */
// private static final String MAGNET_DEFAULT = "/magnet10/default.js?";
/** Magnet request for a paused response */
// private static final String MAGNET_PAUSE = "/magnet10/pause";
/** Start of Magnet URI */
private static final String MAGNET = "magnet:?";
/** Magnet detail command */
private static final String MAGNET_DETAIL = "magcmd/detail?";
private static final String LIBRARY_URL = "/library/";
private String lastCommand;
private long lastCommandTime;
private long MIN_REQUEST_INTERVAL = 1500;
private final ExternalControl externalControl;
private LibraryManager libraryManager;
@Inject
public LocalHTTPAcceptor(ExternalControl externalControl, LibraryManager libraryManager,
AuthenticationInterceptor requestAuthenticator) {
super(createDefaultParams(LimeWireUtils.getHttpServer(), Constants.TIMEOUT),
requestAuthenticator, SUPPORTED_METHODS);
this.externalControl = externalControl;
this.libraryManager = libraryManager;
registerHandler("magnet:", new MagnetCommandRequestHandler());
registerHandler("/magnet10/default.js", new MagnetCommandRequestHandler());
registerHandler("/magnet10/pause", new MagnetPauseRequestHandler());
registerHandler("/magcmd/detail", new MagnetDetailRequestHandler());
registerHandler("/script/asset/*", new FileRequestHandler());
registerHandler("/library/*", new LibraryRequestHandler());
registerHandler("/crossdomain.xml", new CrossDomainRequestHandler());
// TODO figure out which files we want to serve from the local file system
//registerHandler("*", new FileRequestHandler(new File("root"), new BasicMimeTypeProvider()));
}
@Inject
void register(org.limewire.lifecycle.ServiceRegistry registry) {
registry.register(this);
}
@Override
public String getServiceName() {
return org.limewire.i18n.I18nMarker.marktr("Magnet Processor");
}
private class MagnetCommandRequestHandler extends SimpleNHttpRequestHandler {
public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request,
HttpContext context) throws HttpException, IOException {
return null;
}
@Override
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
final String uri = request.getRequestLine().getUri();
magnetExecutor.execute(new Runnable() {
public void run() {
try {
triggerMagnetHandling(uri);
} catch(IOException ignored) {}
}
});
}
}
private class MagnetPauseRequestHandler extends SimpleNHttpRequestHandler {
public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request,
HttpContext context) throws HttpException, IOException {
return null;
}
@Override
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
response.setStatusCode(HttpStatus.SC_NO_CONTENT);
magnetExecutor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
}
}
});
}
}
private static class MagnetDetailRequestHandler extends SimpleNHttpRequestHandler {
public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request,
HttpContext context) throws HttpException, IOException {
return null;
}
@Override
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
String uri = request.getRequestLine().getUri();
int i = uri.indexOf(MAGNET_DETAIL);
String command = uri.substring(i + MAGNET_DETAIL.length());
String page = MagnetHTML.buildMagnetDetailPage(command);
NStringEntity entity = new NStringEntity(page);
entity.setContentType("text/html");
response.setEntity(entity);
}
}
private class CrossDomainRequestHandler extends SimpleNHttpRequestHandler {
public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request,
HttpContext context) throws HttpException, IOException {
return null;
}
@Override
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
String page = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
page += "<cross-domain-policy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.adobe.com/xml/schemas/PolicyFile.xsd\">";
page += "<allow-access-from domain=\"*.opentape.fm\" />";
page += "</cross-domain-policy>";
NStringEntity entity = new NStringEntity(page);
entity.setContentType("text/html");
response.setEntity(entity);
}
}
private class FileRequestHandler extends SimpleNHttpRequestHandler {
public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request,
HttpContext context) throws HttpException, IOException {
return null;
}
@Override
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
String uri = request.getRequestLine().getUri();
int i = uri.indexOf("/script/asset/");
String filepath = uri.substring(i + "/script/asset/".length());
i = filepath.lastIndexOf('/');
String filename = filepath.substring(i + 1);
i = filename.lastIndexOf('.');
String extension = filename.substring(i + 1);
System.out.println(extension);
System.out.println(filepath);
File file = new File("../../core/com/limegroup/scripting/resources/assets/" + filepath);
NFileEntity entity = new NFileEntity(file, "application/binary");
if(extension.contentEquals("js")) {
entity.setContentType("text/javascript");
} else if(extension.contentEquals("css")) {
entity.setContentType("text/css");
} else if(extension.contentEquals("swf")) {
entity.setContentType("application/x-shockwave-flash");
} else if(extension.contentEquals("html")) {
entity.setContentType("text/html");
} else {
entity.setContentType("application/binary");
}
response.setEntity(entity);
}
}
private class LibraryRequestHandler extends SimpleNHttpRequestHandler {
public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request,
HttpContext context) throws HttpException, IOException {
return null;
}
@Override
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
AbstractHttpEntity entity;
String uri = request.getRequestLine().getUri();
int i = uri.indexOf(LIBRARY_URL);
String sha1 = uri.substring(i + LIBRARY_URL.length());
if(sha1.indexOf("?") != -1) {
sha1 = sha1.substring(0, sha1.indexOf("?"));
}
System.out.println("sha1:" + sha1);
com.limegroup.gnutella.URN urn = com.limegroup.gnutella.URN.createSHA1Urn(sha1);
if(libraryManager.getLibraryManagedList().contains(urn)) {
FileDesc fileDesc = libraryManager.getLibraryManagedList().getFileDescsByURN(urn).get(0);
entity = new NFileEntity(fileDesc.getFile(), "application/binary");
entity.setContentType("application/binary");
response.setHeader("Content-disposition", "attachment; filename=\"" + fileDesc.getFileName() + "\";");
} else {
entity = new NStringEntity("File not found: " + sha1);
entity.setContentType("text/plain");
}
response.setEntity(entity);
}
}
private synchronized void triggerMagnetHandling(String uri)
throws IOException {
int i = uri.indexOf("?");
if (i == -1) {
throw new IOException("Invalid command");
}
String command = uri.substring(i + 1);
// suppress duplicate requests from some browsers
long currentTime = System.currentTimeMillis();
if (!command.equals(lastCommand) || (currentTime - lastCommandTime) >= MIN_REQUEST_INTERVAL) {
// trigger an operation
externalControl.handleMagnetRequest(MAGNET + command);
lastCommand = command;
lastCommandTime = currentTime;
} else {
LOG.warn("Ignoring duplicate request: " + command);
}
}
}