forked from I2P_Developers/i2p.i2p
beginning of branch i2p.i2p.i2p
This commit is contained in:
47
apps/httptunnel/java/build.xml
Normal file
47
apps/httptunnel/java/build.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="httptunnel">
|
||||
<target name="all" depends="clean, build" />
|
||||
<target name="build" depends="builddep, jar" />
|
||||
<target name="builddep">
|
||||
<ant dir="../../ministreaming/java/" target="build" />
|
||||
<ant dir="../../../core/java/" target="build" />
|
||||
</target>
|
||||
<target name="compile">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac
|
||||
srcdir="./src"
|
||||
debug="true"
|
||||
destdir="./build/obj"
|
||||
classpath="../../../core/java/build/i2p.jar:../../ministreaming/java/build/mstreaming.jar" />
|
||||
</target>
|
||||
<target name="jar" depends="compile">
|
||||
<jar destfile="./build/httptunnel.jar" basedir="./build/obj" includes="**/*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.httptunnel.HTTPTunnel" />
|
||||
<attribute name="Class-Path" value="i2p.jar mstreaming.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="javadoc">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/javadoc" />
|
||||
<javadoc
|
||||
sourcepath="./src:../../../core/java/src:../../ministreaming/java/src" destdir="./build/javadoc"
|
||||
packagenames="*"
|
||||
use="true"
|
||||
splitindex="true"
|
||||
windowtitle="HTTPTunnel" />
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<ant dir="../../../core/java/" target="cleandep" />
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<ant dir="../../../core/java/" target="distclean" />
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Listens on a port for HTTP connections.
|
||||
*/
|
||||
public class HTTPListener extends Thread {
|
||||
|
||||
private static final Log _log = new Log(HTTPListener.class);
|
||||
|
||||
private int port;
|
||||
private String listenHost;
|
||||
private SocketManagerProducer smp;
|
||||
|
||||
public HTTPListener(SocketManagerProducer smp, int port,
|
||||
String listenHost) {
|
||||
this.smp = smp;
|
||||
this.port = port;
|
||||
start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
InetAddress lh = listenHost == null
|
||||
? null
|
||||
: InetAddress.getByName(listenHost);
|
||||
ServerSocket ss = new ServerSocket(port, 0, lh);
|
||||
while(true) {
|
||||
Socket s = ss.accept();
|
||||
new HTTPSocketHandler(this, s);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while accepting connections", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean proxyUsed=false;
|
||||
|
||||
public boolean firstProxyUse() {
|
||||
// FIXME: check a config option here
|
||||
if (true) return false;
|
||||
if (proxyUsed) {
|
||||
return false;
|
||||
} else {
|
||||
proxyUsed=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public SocketManagerProducer getSMP() {
|
||||
return smp;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public void handleNotImplemented(OutputStream out) throws IOException {
|
||||
out.write(("HTTP/1.1 200 Document following\n\n"+
|
||||
"<h1>Feature not implemented</h1>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.httptunnel.handler.RootHandler;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handles a single HTTP socket connection.
|
||||
*/
|
||||
public class HTTPSocketHandler extends Thread {
|
||||
|
||||
private static final Log _log = new Log(HTTPSocketHandler.class);
|
||||
|
||||
private Socket s;
|
||||
private HTTPListener httpl;
|
||||
private RootHandler h;
|
||||
|
||||
public HTTPSocketHandler(HTTPListener httpl, Socket s) {
|
||||
this.httpl = httpl;
|
||||
this.s=s;
|
||||
h = RootHandler.getInstance();
|
||||
start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = new BufferedInputStream(s.getInputStream());
|
||||
out = new BufferedOutputStream(s.getOutputStream());
|
||||
Request req = new Request(in);
|
||||
h.handle(req, httpl, out);
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling data", ex);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
if (out != null) {
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("IOException in finalizer", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
apps/httptunnel/java/src/net/i2p/httptunnel/HTTPTunnel.java
Normal file
110
apps/httptunnel/java/src/net/i2p/httptunnel/HTTPTunnel.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* HTTPTunnel
|
||||
* (c) 2003 - 2004 mihi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* In addition, as a special exception, mihi gives permission to link
|
||||
* the code of this program with the proprietary Java implementation
|
||||
* provided by Sun (or other vendors as well), and distribute linked
|
||||
* combinations including the two. You must obey the GNU General
|
||||
* Public License in all respects for all of the code used other than
|
||||
* the proprietary Java implementation. If you modify this file, you
|
||||
* may extend this exception to your version of the file, but you are
|
||||
* not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
|
||||
/**
|
||||
* HTTPTunnel main class.
|
||||
*/
|
||||
public class HTTPTunnel {
|
||||
|
||||
/**
|
||||
* Create a HTTPTunnel instance.
|
||||
*
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param mcDonaldsMode whether to throw away a manager after use
|
||||
* @param listenPort which port to listen on
|
||||
*/
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers,
|
||||
boolean mcDonaldsMode, int listenPort) {
|
||||
this(initialManagers, maxManagers, mcDonaldsMode, listenPort,
|
||||
"127.0.0.1", 7654);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTTPTunnel instance.
|
||||
*
|
||||
* @param initialManagers a list of socket managers to use
|
||||
* @param maxManagers how many managers to have in the cache
|
||||
* @param mcDonaldsMode whether to throw away a manager after use
|
||||
* @param listenPort which port to listen on
|
||||
* @param i2cpAddress the I2CP address
|
||||
* @param i2cpPort the I2CP port
|
||||
*/
|
||||
public HTTPTunnel(I2PSocketManager[] initialManagers, int maxManagers,
|
||||
boolean mcDonaldsMode, int listenPort,
|
||||
String i2cpAddress, int i2cpPort) {
|
||||
SocketManagerProducer smp =
|
||||
new SocketManagerProducer(initialManagers, maxManagers,
|
||||
mcDonaldsMode, i2cpAddress, i2cpPort);
|
||||
new HTTPListener(smp, listenPort, "127.0.0.1");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String host = "127.0.0.1";
|
||||
int port = 7654, max = 1;
|
||||
boolean mc = false;
|
||||
if (args.length >1) {
|
||||
if (args.length == 4) {
|
||||
host = args[2];
|
||||
port = Integer.parseInt(args[3]);
|
||||
} else if (args.length != 2) {
|
||||
showInfo(); return;
|
||||
}
|
||||
max = Integer.parseInt(args[1]);
|
||||
} else if (args.length != 1) {
|
||||
showInfo(); return;
|
||||
}
|
||||
if (max == 0) {
|
||||
max = 1;
|
||||
} else if (max <0) {
|
||||
max = -max;
|
||||
mc = true;
|
||||
}
|
||||
new HTTPTunnel(null, max, mc, Integer.parseInt(args[0]), host, port);
|
||||
}
|
||||
|
||||
private static void showInfo() {
|
||||
System.out.println
|
||||
("Usage: java HTTPTunnel <listenPort> [<max> "+
|
||||
"[<i2cphost> <i2cpport>]]\n"+
|
||||
" <listenPort> port to listen for browsers\n"+
|
||||
" <max> max number of SocketMangers in pool, "+
|
||||
"use neg. number\n"+
|
||||
" to use each SocketManager only once "+
|
||||
"(default: 1)\n"+
|
||||
" <i2cphost> host to connect to the router "+
|
||||
"(default: 127.0.0.1)\n"+
|
||||
" <i2cpport> port to connect to the router "+
|
||||
"(default: 7654)");
|
||||
}
|
||||
}
|
||||
130
apps/httptunnel/java/src/net/i2p/httptunnel/Request.java
Normal file
130
apps/httptunnel/java/src/net/i2p/httptunnel/Request.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* A HTTP request (GET or POST). This will be passed to a hander for
|
||||
* handling it.
|
||||
*/
|
||||
public class Request {
|
||||
|
||||
private static final Log _log = new Log(Request.class);
|
||||
|
||||
// all strings are forced to be ISO-8859-1 encoding
|
||||
private String method;
|
||||
private String url;
|
||||
private String proto;
|
||||
private String params;
|
||||
private String postData;
|
||||
|
||||
public Request(InputStream in) throws IOException {
|
||||
BufferedReader br = new BufferedReader
|
||||
(new InputStreamReader(in, "ISO-8859-1"));
|
||||
String line = br.readLine();
|
||||
if (line == null) { // no data at all
|
||||
method = null;
|
||||
_log.error("Connection but no data");
|
||||
return;
|
||||
}
|
||||
int pos = line.indexOf(" ");
|
||||
if (pos == -1) {
|
||||
method = line;
|
||||
url="";
|
||||
_log.error("Malformed HTTP request: "+line);
|
||||
} else {
|
||||
method = line.substring(0,pos);
|
||||
url=line.substring(pos+1);
|
||||
}
|
||||
proto="";
|
||||
pos = url.indexOf(" ");
|
||||
if (pos != -1) {
|
||||
proto=url.substring(pos); // leading space intended
|
||||
url = url.substring(0,pos);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(512);
|
||||
while((line=br.readLine()) != null) {
|
||||
if (line.length() == 0) break;
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
params = sb.toString(); // no leading empty line!
|
||||
sb = new StringBuffer();
|
||||
// hack for POST requests, ripped from HttpClient
|
||||
// this won't work for large POSTDATA
|
||||
// FIXME: do this better, please.
|
||||
if (!method.equals("GET")) {
|
||||
while (br.ready()) { // empty the buffer (POST requests)
|
||||
int i=br.read();
|
||||
if (i != -1) {
|
||||
sb.append((char)i);
|
||||
}
|
||||
}
|
||||
postData = sb.toString();
|
||||
} else {
|
||||
postData="";
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] toByteArray() throws IOException {
|
||||
if (method == null) return null;
|
||||
return toISO8859_1String().getBytes("ISO-8859-1");
|
||||
|
||||
}
|
||||
|
||||
private String toISO8859_1String() throws IOException {
|
||||
if (method == null) return null;
|
||||
return method+" "+url+proto+"\r\n"+params+"\r\n"+postData;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setURL(String newURL) {
|
||||
url=newURL;
|
||||
}
|
||||
|
||||
public String getParam(String name) {
|
||||
try {
|
||||
BufferedReader br= new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith(name)) {
|
||||
return line.substring(name.length());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setParam(String name, String value) {
|
||||
try {
|
||||
StringBuffer sb = new StringBuffer(params.length()+value.length());
|
||||
BufferedReader br= new BufferedReader(new StringReader(params));
|
||||
String line;
|
||||
boolean replaced = false;
|
||||
while((line=br.readLine()) != null) {
|
||||
if (line.startsWith(name)) {
|
||||
replaced=true;
|
||||
if (value == null) continue; // kill param
|
||||
line = name+value;
|
||||
}
|
||||
sb.append(line).append("\r\n");
|
||||
}
|
||||
if (!replaced && value != null) {
|
||||
sb.append(name).append(value).append("\r\n");
|
||||
}
|
||||
params=sb.toString();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error getting parameter", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package net.i2p.httptunnel;
|
||||
|
||||
import java.util.*;
|
||||
import net.i2p.client.streaming.*;
|
||||
|
||||
/**
|
||||
* Produces SocketManagers in a thread and gives them to those who
|
||||
* need them.
|
||||
*/
|
||||
public class SocketManagerProducer extends Thread {
|
||||
|
||||
private ArrayList myManagers = new ArrayList();
|
||||
private HashMap usedManagers = new HashMap();
|
||||
private int port;
|
||||
private String host;
|
||||
private int maxManagers;
|
||||
private boolean mcDonalds;
|
||||
|
||||
public SocketManagerProducer(I2PSocketManager[] initialManagers,
|
||||
int maxManagers,
|
||||
boolean mcDonaldsMode,
|
||||
String host, int port) {
|
||||
if (maxManagers < 1) {
|
||||
throw new IllegalArgumentException("maxManagers < 1");
|
||||
}
|
||||
this.host=host;
|
||||
this.port=port;
|
||||
mcDonalds=mcDonaldsMode;
|
||||
if (initialManagers != null) {
|
||||
myManagers.addAll(Arrays.asList(initialManagers));
|
||||
}
|
||||
this.maxManagers=maxManagers;
|
||||
mcDonalds=mcDonaldsMode;
|
||||
setDaemon(true);
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread producing new SocketManagers.
|
||||
*/
|
||||
public void run() {
|
||||
while (true) {
|
||||
synchronized(this) {
|
||||
// without mcDonalds mode, we most probably need no
|
||||
// new managers.
|
||||
while (!mcDonalds && myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
}
|
||||
// produce a new manager, regardless whether it is needed
|
||||
// or not. Do not synchronized this part, since it can be
|
||||
// quite time-consuming.
|
||||
I2PSocketManager newManager =
|
||||
I2PSocketManagerFactory.createManager(host, port,
|
||||
new Properties());
|
||||
// when done, check if it is needed.
|
||||
synchronized(this) {
|
||||
while(myManagers.size() == maxManagers) {
|
||||
myWait();
|
||||
}
|
||||
myManagers.add(newManager);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a manager for connecting to a given destination. Each
|
||||
* destination will always get the same manager.
|
||||
*
|
||||
* @param dest the destination to connect to
|
||||
* @return the SocketManager to use
|
||||
*/
|
||||
public synchronized I2PSocketManager getManager(String dest) {
|
||||
I2PSocketManager result = (I2PSocketManager) usedManagers.get(dest);
|
||||
if (result == null) {
|
||||
result = getManager();
|
||||
usedManagers.put(dest,result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a "new" SocketManager. Depending on the anonymity settings,
|
||||
* this can be a completely new one or one randomly selected from
|
||||
* a pool.
|
||||
*
|
||||
* @return the SocketManager to use
|
||||
*/
|
||||
public synchronized I2PSocketManager getManager() {
|
||||
while (myManagers.size() == 0) {
|
||||
myWait(); // no manager here, so wait until one is produced
|
||||
}
|
||||
int which = (int)(Math.random()*myManagers.size());
|
||||
I2PSocketManager result = (I2PSocketManager) myManagers.get(which);
|
||||
if (mcDonalds) {
|
||||
myManagers.remove(which);
|
||||
notifyAll();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void myWait() {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Chain multiple filters. Decorator pattern...
|
||||
*/
|
||||
public class ChainFilter implements Filter {
|
||||
|
||||
private static final Log _log = new Log(ChainFilter.class);
|
||||
|
||||
public Collection filters;
|
||||
|
||||
public ChainFilter(Collection filters) {
|
||||
this.filters=filters;
|
||||
}
|
||||
|
||||
public byte[] filter(byte[] toFilter) {
|
||||
byte[] buf = toFilter;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
buf = f.filter(buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
public byte[] finish() {
|
||||
// this is a bit complicated. Think about it...
|
||||
try {
|
||||
byte[] buf = EMPTY;
|
||||
for (Iterator it = filters.iterator(); it.hasNext();) {
|
||||
Filter f = (Filter) it.next();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (buf.length != 0) {
|
||||
baos.write(f.filter(buf));
|
||||
}
|
||||
baos.write(f.finish());
|
||||
buf = baos.toByteArray();
|
||||
}
|
||||
return buf;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error chaining filters", ex);
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
/**
|
||||
* A generic filtering interface.
|
||||
*/
|
||||
public interface Filter {
|
||||
|
||||
/**
|
||||
* An empty byte array.
|
||||
*/
|
||||
public static final byte[] EMPTY = new byte[0];
|
||||
|
||||
/**
|
||||
* Filter some data. Not all filtered data need to be returned.
|
||||
*/
|
||||
public byte[] filter(byte[] toFilter);
|
||||
|
||||
/**
|
||||
* Data stream has finished. Return all of the rest data.
|
||||
*/
|
||||
public byte[] finish();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.i2p.httptunnel.filter;
|
||||
|
||||
/**
|
||||
* A filter letting everything pass as is.
|
||||
*/
|
||||
public class NullFilter implements Filter {
|
||||
|
||||
public byte[] filter(byte[] toFilter) {
|
||||
return toFilter;
|
||||
}
|
||||
|
||||
public byte[] finish() {
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
import net.i2p.httptunnel.Request;
|
||||
import net.i2p.httptunnel.SocketManagerProducer;
|
||||
import net.i2p.httptunnel.filter.Filter;
|
||||
import net.i2p.httptunnel.filter.NullFilter;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler for browsing Eepsites.
|
||||
*/
|
||||
public class EepHandler {
|
||||
|
||||
private static final Log _log = new Log(EepHandler.class);
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
||||
/* package private */ EepHandler(ErrorHandler eh) {
|
||||
errorHandler=eh;
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
boolean fromProxy, String destination)
|
||||
throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = NamingService.getInstance().lookup(destination);
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out,
|
||||
"Could not lookup host: "+destination);
|
||||
return;
|
||||
}
|
||||
I2PSocketManager sm = smp.getManager(destination);
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
req.setParam("Host: ", dest.toBase64());
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean handle(Request req, Filter f, OutputStream out,
|
||||
Destination dest, I2PSocketManager sm)
|
||||
throws IOException {
|
||||
I2PSocket s = null;
|
||||
boolean written = false;
|
||||
try {
|
||||
synchronized(sm) {
|
||||
s = sm.connect(dest, new I2PSocketOptions());
|
||||
}
|
||||
InputStream in = new BufferedInputStream(s.getInputStream());
|
||||
OutputStream sout = new BufferedOutputStream(s.getOutputStream());
|
||||
sout.write(req.toByteArray());
|
||||
sout.flush();
|
||||
byte[] buffer = new byte[16384], filtered;
|
||||
int len;
|
||||
while ((len=in.read(buffer)) != -1) {
|
||||
if (len != buffer.length) {
|
||||
byte[] b2 = new byte[len];
|
||||
System.arraycopy(buffer, 0, b2, 0, len);
|
||||
filtered=f.filter(b2);
|
||||
} else {
|
||||
filtered=f.filter(buffer);
|
||||
}
|
||||
written=true;
|
||||
out.write(filtered);
|
||||
}
|
||||
filtered=f.finish();
|
||||
written=true;
|
||||
out.write(filtered);
|
||||
out.flush();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while handling eepsite request");
|
||||
return written;
|
||||
} finally {
|
||||
if (s != null) s.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
import net.i2p.httptunnel.Request;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler for general error messages.
|
||||
*/
|
||||
public class ErrorHandler {
|
||||
|
||||
private static final Log _log = new Log(ErrorHandler.class);
|
||||
|
||||
/* package private */ ErrorHandler() {
|
||||
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl,
|
||||
OutputStream out, String error) throws IOException {
|
||||
// FIXME: Make nicer messages for more likely errors.
|
||||
out.write(("HTTP/1.1 500 Internal Server Error\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.write(("<html><head><title>"+error+"</title></head><body><h1>"+
|
||||
error+"</h1>An internal error occurred while "+
|
||||
"handling a request by HTTPTunnel:<br><b>"+error+
|
||||
"</b><h2>Complete request:</h2><b>---</b><br><i><pre>\r\n")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.write(req.toByteArray());
|
||||
out.write(("</pre></i><br><b>---</b></body></html>")
|
||||
.getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
import net.i2p.httptunnel.Request;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler for requests that do not require any connection to anyone
|
||||
* (except errors).
|
||||
*/
|
||||
public class LocalHandler {
|
||||
|
||||
private static final Log _log = new Log(LocalHandler.class);
|
||||
|
||||
/* package private */ LocalHandler() {
|
||||
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
boolean fromProxy) throws IOException {
|
||||
//FIXME: separate multiple pages, not only a start page
|
||||
//FIXME: provide some info on this page
|
||||
out.write(("HTTP/1.1 200 Document following\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n"+
|
||||
"<html><head><title>Welcome to I2P HTTPTunnel</title>"+
|
||||
"</head><body><h1>Welcome to I2P HTTPTunnel</h1>You can "+
|
||||
"browse Eepsites by adding an eepsite name to the request."+
|
||||
"</body></html>").getBytes("ISO-8859-1"));
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public void handleProxyConfWarning(Request req, HTTPListener httpl,
|
||||
OutputStream out) throws IOException {
|
||||
//FIXME
|
||||
throw new IOException("jrandom ate the deprecated method. mooo");
|
||||
//httpl.handleNotImplemented(out);
|
||||
|
||||
}
|
||||
|
||||
public void handleHTTPWarning(Request req, HTTPListener httpl,
|
||||
OutputStream out, boolean fromProxy)
|
||||
throws IOException {
|
||||
// FIXME
|
||||
throw new IOException("jrandom ate the deprecated method. mooo");
|
||||
//httpl.handleNotImplemented(out);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
import net.i2p.httptunnel.Request;
|
||||
import net.i2p.httptunnel.SocketManagerProducer;
|
||||
import net.i2p.httptunnel.filter.Filter;
|
||||
import net.i2p.httptunnel.filter.NullFilter;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handler for proxying "normal" HTTP requests.
|
||||
*/
|
||||
public class ProxyHandler extends EepHandler {
|
||||
|
||||
private static final Log _log = new Log(ErrorHandler.class);
|
||||
|
||||
/* package private */ ProxyHandler(ErrorHandler eh) {
|
||||
super(eh);
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
boolean fromProxy) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = findProxy();
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out,
|
||||
"Could not find proxy");
|
||||
return;
|
||||
}
|
||||
// one manager for all proxy requests
|
||||
I2PSocketManager sm = smp.getManager("--proxy--");
|
||||
Filter f = new NullFilter(); //FIXME: use other filter
|
||||
if (!handle(req, f, out, dest, sm)) {
|
||||
errorHandler.handle(req, httpl, out, "Unable to reach peer");
|
||||
}
|
||||
}
|
||||
|
||||
private Destination findProxy() {
|
||||
//FIXME!
|
||||
return NamingService.getInstance().lookup("squid.i2p");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.i2p.httptunnel.handler;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
import net.i2p.httptunnel.Request;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Main handler for all requests. Dispatches requests to other handlers.
|
||||
*/
|
||||
public class RootHandler {
|
||||
|
||||
private static final Log _log = new Log(RootHandler.class);
|
||||
|
||||
private RootHandler() {
|
||||
errorHandler=new ErrorHandler();
|
||||
localHandler=new LocalHandler();
|
||||
proxyHandler=new ProxyHandler(errorHandler);
|
||||
eepHandler=new EepHandler(errorHandler);
|
||||
}
|
||||
|
||||
private ErrorHandler errorHandler;
|
||||
private ProxyHandler proxyHandler;
|
||||
private LocalHandler localHandler;
|
||||
private EepHandler eepHandler;
|
||||
|
||||
private static RootHandler instance;
|
||||
|
||||
public static synchronized RootHandler getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new RootHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void handle(Request req, HTTPListener httpl,
|
||||
OutputStream out) throws IOException {
|
||||
String url=req.getURL();
|
||||
System.out.println(url);
|
||||
boolean byProxy = false;
|
||||
int pos;
|
||||
if (url.startsWith("http://")) { // access via proxy
|
||||
byProxy=true;
|
||||
if (httpl.firstProxyUse()) {
|
||||
localHandler.handleProxyConfWarning(req,httpl,out);
|
||||
return;
|
||||
}
|
||||
url = url.substring(7);
|
||||
pos = url.indexOf("/");
|
||||
String host;
|
||||
String rest;
|
||||
if (pos == -1) {
|
||||
errorHandler.handle(req, httpl, out, "No host end in URL");
|
||||
return;
|
||||
} else {
|
||||
host = url.substring(0,pos);
|
||||
url = url.substring(pos);
|
||||
if ("i2p".equals(host) || "i2p.i2p".equals(host)) {
|
||||
// normal request; go on below...
|
||||
} else if (host.endsWith(".i2p")) {
|
||||
// "old" service request, send a redirect...
|
||||
out.write(("HTTP/1.1 302 Moved\r\nLocation: "+
|
||||
"http://i2p.i2p/"+host+url+
|
||||
"\r\n\r\n").getBytes("ISO-8859-1"));
|
||||
return;
|
||||
} else {
|
||||
// this is for proxying to the real web
|
||||
proxyHandler.handle(req, httpl, out, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (url.equals("/")) { // main page
|
||||
url="/_/local/index";
|
||||
} else if (!url.startsWith("/")) {
|
||||
errorHandler.handle(req, httpl, out,
|
||||
"No leading slash in URL: "+url);
|
||||
return;
|
||||
}
|
||||
String dest;
|
||||
url=url.substring(1);
|
||||
pos = url.indexOf("/");
|
||||
if (pos == -1) {
|
||||
dest=url;
|
||||
url="/";
|
||||
} else {
|
||||
dest = url.substring(0,pos);
|
||||
url=url.substring(pos);
|
||||
}
|
||||
req.setURL(url);
|
||||
if (dest.equals("_")) { // no eepsite
|
||||
if (url.startsWith("/local/")) { // local request
|
||||
req.setURL(url.substring(6));
|
||||
localHandler.handle(req, httpl, out, byProxy);
|
||||
} else if (url.startsWith("/http/")) { // http warning
|
||||
localHandler.handleHTTPWarning(req, httpl, out, byProxy);
|
||||
} else if (url.startsWith("/proxy/")) { // http proxying
|
||||
req.setURL("http://"+url.substring(7));
|
||||
proxyHandler.handle(req, httpl, out, byProxy);
|
||||
} else {
|
||||
errorHandler.handle(req, httpl, out,
|
||||
"No local handler for this URL: "+url);
|
||||
}
|
||||
} else {
|
||||
eepHandler.handle(req, httpl, out, byProxy, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user