forked from I2P_Developers/i2p.i2p
i2ptunnel HTTP client: Replace all getBytes() calls
with a Writer or getBytes("UTF-8") for efficiency and to avoid encoding issues. Store strings as strings, not bytes. Catch IOEs to prevent cascading error pages. Minor cleanups
This commit is contained in:
@@ -328,9 +328,9 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
|||||||
if (compressed > 0 && expanded > 0) {
|
if (compressed > 0 && expanded > 0) {
|
||||||
// only update the stats if we did something
|
// only update the stats if we did something
|
||||||
double ratio = compressed/expanded;
|
double ratio = compressed/expanded;
|
||||||
_context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio), 0);
|
_context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio));
|
||||||
_context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed, 0);
|
_context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed);
|
||||||
_context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded, 0);
|
_context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -59,24 +59,22 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
|
|||||||
|
|
||||||
public static final String AUTH_REALM = "I2P SSL Proxy";
|
public static final String AUTH_REALM = "I2P SSL Proxy";
|
||||||
|
|
||||||
private final static byte[] ERR_BAD_PROTOCOL =
|
private final static String ERR_BAD_PROTOCOL =
|
||||||
("HTTP/1.1 405 Bad Method\r\n"+
|
"HTTP/1.1 405 Bad Method\r\n"+
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||||
"Cache-control: no-cache\r\n"+
|
"Cache-control: no-cache\r\n"+
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
"<html><body><H1>I2P ERROR: METHOD NOT ALLOWED</H1>"+
|
"<html><body><H1>I2P ERROR: METHOD NOT ALLOWED</H1>"+
|
||||||
"The request uses a bad protocol. "+
|
"The request uses a bad protocol. "+
|
||||||
"The Connect Proxy supports CONNECT requests ONLY. Other methods such as GET are not allowed - Maybe you wanted the HTTP Proxy?.<BR>")
|
"The Connect Proxy supports CONNECT requests ONLY. Other methods such as GET are not allowed - Maybe you wanted the HTTP Proxy?.<BR>";
|
||||||
.getBytes();
|
|
||||||
|
|
||||||
private final static byte[] ERR_LOCALHOST =
|
private final static String ERR_LOCALHOST =
|
||||||
("HTTP/1.1 403 Access Denied\r\n"+
|
"HTTP/1.1 403 Access Denied\r\n"+
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||||
"Cache-control: no-cache\r\n"+
|
"Cache-control: no-cache\r\n"+
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
|
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
|
||||||
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>")
|
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>";
|
||||||
.getBytes();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||||
@@ -273,7 +271,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
|
|||||||
|
|
||||||
Destination clientDest = _context.namingService().lookup(destination);
|
Destination clientDest = _context.namingService().lookup(destination);
|
||||||
if (clientDest == null) {
|
if (clientDest == null) {
|
||||||
byte[] header;
|
String header;
|
||||||
if (usingWWWProxy)
|
if (usingWWWProxy)
|
||||||
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
|
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
|
||||||
else
|
else
|
||||||
@@ -289,7 +287,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
|
|||||||
if (usingWWWProxy)
|
if (usingWWWProxy)
|
||||||
data = newRequest.toString().getBytes("ISO-8859-1");
|
data = newRequest.toString().getBytes("ISO-8859-1");
|
||||||
else
|
else
|
||||||
response = SUCCESS_RESPONSE;
|
response = SUCCESS_RESPONSE.getBytes("UTF-8");
|
||||||
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
|
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
|
||||||
Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
|
Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
|
||||||
// we are called from an unlimited thread pool, so run inline
|
// we are called from an unlimited thread pool, so run inline
|
||||||
@@ -311,10 +309,10 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeErrorMessage(byte[] errMessage, OutputStream out) throws IOException {
|
private static void writeErrorMessage(String errMessage, OutputStream out) throws IOException {
|
||||||
if (out == null)
|
if (out == null)
|
||||||
return;
|
return;
|
||||||
out.write(errMessage);
|
out.write(errMessage.getBytes("UTF-8"));
|
||||||
writeFooter(out);
|
writeFooter(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,9 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
package net.i2p.i2ptunnel;
|
package net.i2p.i2ptunnel;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -84,13 +87,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
/**
|
/**
|
||||||
* These are backups if the xxx.ht error page is missing.
|
* These are backups if the xxx.ht error page is missing.
|
||||||
*/
|
*/
|
||||||
private final static byte[] ERR_REQUEST_DENIED =
|
private final static String ERR_REQUEST_DENIED =
|
||||||
("HTTP/1.1 403 Access Denied\r\n" +
|
"HTTP/1.1 403 Access Denied\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
|
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
|
||||||
"You attempted to connect to a non-I2P website or location.<BR>").getBytes();
|
"You attempted to connect to a non-I2P website or location.<BR>";
|
||||||
|
|
||||||
/*****
|
/*****
|
||||||
private final static byte[] ERR_TIMEOUT =
|
private final static byte[] ERR_TIMEOUT =
|
||||||
@@ -105,17 +108,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
"the following Destination:<BR><BR>")
|
"the following Destination:<BR><BR>")
|
||||||
.getBytes();
|
.getBytes();
|
||||||
*****/
|
*****/
|
||||||
private final static byte[] ERR_NO_OUTPROXY =
|
private final static String ERR_NO_OUTPROXY =
|
||||||
("HTTP/1.1 503 Service Unavailable\r\n" +
|
"HTTP/1.1 503 Service Unavailable\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: No outproxy found</H1>" +
|
"<html><body><H1>I2P ERROR: No outproxy found</H1>" +
|
||||||
"Your request was for a site outside of I2P, but you have no " +
|
"Your request was for a site outside of I2P, but you have no " +
|
||||||
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel").getBytes();
|
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel";
|
||||||
|
|
||||||
private final static byte[] ERR_AHELPER_CONFLICT =
|
private final static String ERR_AHELPER_CONFLICT =
|
||||||
("HTTP/1.1 409 Conflict\r\n" +
|
"HTTP/1.1 409 Conflict\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
@@ -127,20 +130,20 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
"You can resolve the conflict by considering which key you trust, " +
|
"You can resolve the conflict by considering which key you trust, " +
|
||||||
"and either discarding the addresshelper link, " +
|
"and either discarding the addresshelper link, " +
|
||||||
"discarding the host entry from your host database, " +
|
"discarding the host entry from your host database, " +
|
||||||
"or naming one of them differently.<p>").getBytes();
|
"or naming one of them differently.<p>";
|
||||||
|
|
||||||
private final static byte[] ERR_AHELPER_NOTFOUND =
|
private final static String ERR_AHELPER_NOTFOUND =
|
||||||
("HTTP/1.1 404 Not Found\r\n" +
|
"HTTP/1.1 404 Not Found\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: Helper key not resolvable.</H1>" +
|
"<html><body><H1>I2P ERROR: Helper key not resolvable.</H1>" +
|
||||||
"The helper key you put for i2paddresshelper= is not resolvable. " +
|
"The helper key you put for i2paddresshelper= is not resolvable. " +
|
||||||
"It seems to be garbage data, or a mistyped b32. Check your URL " +
|
"It seems to be garbage data, or a mistyped b32. Check your URL " +
|
||||||
"to try and fix the helper key to be either a b32 or a base64.").getBytes();
|
"to try and fix the helper key to be either a b32 or a base64.";
|
||||||
|
|
||||||
private final static byte[] ERR_AHELPER_NEW =
|
private final static String ERR_AHELPER_NEW =
|
||||||
("HTTP/1.1 409 New Address\r\n" +
|
"HTTP/1.1 409 New Address\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
@@ -148,42 +151,42 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
"The address helper link you followed is for a new host name that is not in your address book. " +
|
"The address helper link you followed is for a new host name that is not in your address book. " +
|
||||||
"You may either save the destination for this host name to your address book, or remember it only until your router restarts. " +
|
"You may either save the destination for this host name to your address book, or remember it only until your router restarts. " +
|
||||||
"If you save it to your address book, you will not see this message again. " +
|
"If you save it to your address book, you will not see this message again. " +
|
||||||
"If you do not wish to visit this host, click the \"back\" button on your browser.").getBytes();
|
"If you do not wish to visit this host, click the \"back\" button on your browser.";
|
||||||
|
|
||||||
private final static byte[] ERR_BAD_PROTOCOL =
|
private final static String ERR_BAD_PROTOCOL =
|
||||||
("HTTP/1.1 403 Bad Protocol\r\n" +
|
"HTTP/1.1 403 Bad Protocol\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: NON-HTTP PROTOCOL</H1>" +
|
"<html><body><H1>I2P ERROR: NON-HTTP PROTOCOL</H1>" +
|
||||||
"The request uses a bad protocol. " +
|
"The request uses a bad protocol. " +
|
||||||
"The I2P HTTP Proxy supports HTTP and HTTPS requests only. Other protocols such as FTP are not allowed.<BR>").getBytes();
|
"The I2P HTTP Proxy supports HTTP and HTTPS requests only. Other protocols such as FTP are not allowed.<BR>";
|
||||||
|
|
||||||
private final static byte[] ERR_BAD_URI =
|
private final static String ERR_BAD_URI =
|
||||||
("HTTP/1.1 403 Bad URI\r\n" +
|
"HTTP/1.1 403 Bad URI\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: INVALID REQUEST URI</H1>" +
|
"<html><body><H1>I2P ERROR: INVALID REQUEST URI</H1>" +
|
||||||
"The request URI is invalid, and probably contains illegal characters. " +
|
"The request URI is invalid, and probably contains illegal characters. " +
|
||||||
"If you clicked e.g. a forum link, check the end of the URI for any characters the browser has mistakenly added on.<BR>").getBytes();
|
"If you clicked e.g. a forum link, check the end of the URI for any characters the browser has mistakenly added on.<BR>";
|
||||||
|
|
||||||
private final static byte[] ERR_LOCALHOST =
|
private final static String ERR_LOCALHOST =
|
||||||
("HTTP/1.1 403 Access Denied\r\n" +
|
"HTTP/1.1 403 Access Denied\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
|
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
|
||||||
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>").getBytes();
|
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>";
|
||||||
|
|
||||||
private final static byte[] ERR_INTERNAL_SSL =
|
private final static String ERR_INTERNAL_SSL =
|
||||||
("HTTP/1.1 403 SSL Rejected\r\n" +
|
"HTTP/1.1 403 SSL Rejected\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"<html><body><H1>I2P ERROR: SSL to I2P address rejected</H1>" +
|
"<html><body><H1>I2P ERROR: SSL to I2P address rejected</H1>" +
|
||||||
"SSL for to .i2p addresses denied by configuration." +
|
"SSL for to .i2p addresses denied by configuration." +
|
||||||
"You may change the configuration in I2PTunnel").getBytes();
|
"You may change the configuration in I2PTunnel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
|
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
|
||||||
@@ -464,10 +467,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(_log.shouldLog(Log.WARN)) {
|
if(_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn(getPrefix(requestId) + "Bad request [" + request + "]", use);
|
_log.warn(getPrefix(requestId) + "Bad request [" + request + "]", use);
|
||||||
}
|
}
|
||||||
out.write(getErrorPage("baduri", ERR_BAD_URI));
|
try {
|
||||||
writeFooter(out);
|
out.write(getErrorPage("baduri", ERR_BAD_URI).getBytes("UTF-8"));
|
||||||
reader.drain();
|
writeFooter(out);
|
||||||
s.close();
|
reader.drain();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,12 +604,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(_log.shouldLog(Log.WARN)) {
|
if(_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn(getPrefix(requestId) + "Could not find destination for " + ahelperKey);
|
_log.warn(getPrefix(requestId) + "Could not find destination for " + ahelperKey);
|
||||||
}
|
}
|
||||||
byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
|
String header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
|
||||||
out.write(header);
|
try {
|
||||||
out.write(("<p>" + _("This seems to be a bad destination:") + " " + ahelperKey + " " + _("i2paddresshelper cannot help you with a destination like that!") + "</p>").getBytes("UTF-8"));
|
out.write(header.getBytes("UTF-8"));
|
||||||
writeFooter(out);
|
out.write(("<p>" + _("This seems to be a bad destination:") + " " + ahelperKey + " " +
|
||||||
// XXX: should closeSocket(s) be in a finally block?
|
_("i2paddresshelper cannot help you with a destination like that!") +
|
||||||
closeSocket(s);
|
"</p>").getBytes("UTF-8"));
|
||||||
|
writeFooter(out);
|
||||||
|
// XXX: should closeSocket(s) be in a finally block?
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ahelperKey = _dest.toBase64();
|
ahelperKey = _dest.toBase64();
|
||||||
@@ -645,11 +660,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
|
|
||||||
// Did addresshelper key conflict?
|
// Did addresshelper key conflict?
|
||||||
if(ahelperConflict) {
|
if(ahelperConflict) {
|
||||||
|
try {
|
||||||
// convert ahelperKey to b32
|
// convert ahelperKey to b32
|
||||||
String alias = getHostName(ahelperKey);
|
String alias = getHostName(ahelperKey);
|
||||||
if(alias.equals("i2p")) {
|
if(alias.equals("i2p")) {
|
||||||
// bad ahelperKey
|
// bad ahelperKey
|
||||||
byte[] header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
|
String header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
|
||||||
writeErrorMessage(header, out, targetRequest, false, destination);
|
writeErrorMessage(header, out, targetRequest, false, destination);
|
||||||
} else {
|
} else {
|
||||||
String trustedURL = requestURI.toASCIIString();
|
String trustedURL = requestURI.toASCIIString();
|
||||||
@@ -663,14 +679,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
String conflictURL = conflictURI.toASCIIString();
|
String conflictURL = conflictURI.toASCIIString();
|
||||||
byte[] header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT);
|
String header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT);
|
||||||
out.write(header);
|
out.write(header.getBytes("UTF-8"));
|
||||||
out.write(_("To visit the destination in your host database, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>.", trustedURL, conflictURL).getBytes("UTF-8"));
|
out.write(_("To visit the destination in your host database, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>.",
|
||||||
out.write(("</p></div>").getBytes());
|
trustedURL, conflictURL).getBytes("UTF-8"));
|
||||||
|
out.write("</p></div>".getBytes("UTF-8"));
|
||||||
writeFooter(out);
|
writeFooter(out);
|
||||||
|
}
|
||||||
|
reader.drain();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
}
|
}
|
||||||
reader.drain();
|
|
||||||
s.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} // end query processing
|
} // end query processing
|
||||||
@@ -700,10 +721,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
} else if(hostLowerCase.equals("localhost") || host.equals("127.0.0.1") ||
|
} else if(hostLowerCase.equals("localhost") || host.equals("127.0.0.1") ||
|
||||||
host.startsWith("192.168.") || host.equals("[::1]")) {
|
host.startsWith("192.168.") || host.equals("[::1]")) {
|
||||||
// if somebody is trying to get to 192.168.example.com, oh well
|
// if somebody is trying to get to 192.168.example.com, oh well
|
||||||
out.write(getErrorPage("localhost", ERR_LOCALHOST));
|
try {
|
||||||
writeFooter(out);
|
out.write(getErrorPage("localhost", ERR_LOCALHOST).getBytes("UTF-8"));
|
||||||
reader.drain();
|
writeFooter(out);
|
||||||
s.close();
|
reader.drain();
|
||||||
|
s.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else if(host.contains(".") || host.startsWith("[")) {
|
} else if(host.contains(".") || host.startsWith("[")) {
|
||||||
if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USE_OUTPROXY_PLUGIN, "true"))) {
|
if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USE_OUTPROXY_PLUGIN, "true"))) {
|
||||||
@@ -748,10 +775,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
|
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
|
||||||
}
|
}
|
||||||
l.log("No outproxy found for the request.");
|
l.log("No outproxy found for the request.");
|
||||||
out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY));
|
try {
|
||||||
writeFooter(out);
|
out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY).getBytes("UTF-8"));
|
||||||
reader.drain();
|
writeFooter(out);
|
||||||
s.close();
|
reader.drain();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
destination = currentProxy;
|
destination = currentProxy;
|
||||||
@@ -769,10 +801,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(_log.shouldLog(Log.WARN)) {
|
if(_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn("NODOTS, NOI2P: " + request);
|
_log.warn("NODOTS, NOI2P: " + request);
|
||||||
}
|
}
|
||||||
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
try {
|
||||||
writeFooter(out);
|
out.write(getErrorPage("denied", ERR_REQUEST_DENIED).getBytes("UTF-8"));
|
||||||
reader.drain();
|
writeFooter(out);
|
||||||
s.close();
|
reader.drain();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} // end host name processing
|
} // end host name processing
|
||||||
|
|
||||||
@@ -898,7 +935,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW);
|
pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW);
|
||||||
}
|
}
|
||||||
if(user != null && pw != null) {
|
if(user != null && pw != null) {
|
||||||
newRequest.append("Proxy-Authorization: Basic ").append(Base64.encode((user + ':' + pw).getBytes(), true)) // true = use standard alphabet
|
newRequest.append("Proxy-Authorization: Basic ")
|
||||||
|
.append(Base64.encode((user + ':' + pw).getBytes("UTF-8"), true)) // true = use standard alphabet
|
||||||
.append("\r\n");
|
.append("\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -915,13 +953,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
|
|
||||||
if(method == null || (destination == null && !usingInternalOutproxy)) {
|
if(method == null || (destination == null && !usingInternalOutproxy)) {
|
||||||
//l.log("No HTTP method found in the request.");
|
//l.log("No HTTP method found in the request.");
|
||||||
if (protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) {
|
try {
|
||||||
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
if (protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) {
|
||||||
} else {
|
out.write(getErrorPage("denied", ERR_REQUEST_DENIED).getBytes("UTF-8"));
|
||||||
out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL));
|
} else {
|
||||||
|
out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL).getBytes("UTF-8"));
|
||||||
|
}
|
||||||
|
writeFooter(out);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
}
|
}
|
||||||
writeFooter(out);
|
|
||||||
s.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -939,23 +982,33 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
_log.warn(getPrefix(requestId) + "Auth required, sending 407");
|
_log.warn(getPrefix(requestId) + "Auth required, sending 407");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
|
try {
|
||||||
writeFooter(out);
|
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes("UTF-8"));
|
||||||
s.close();
|
writeFooter(out);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve local proxy files (images, css linked from error pages)
|
// Serve local proxy files (images, css linked from error pages)
|
||||||
// Ignore all the headers
|
// Ignore all the headers
|
||||||
if(usingInternalServer) {
|
if (usingInternalServer) {
|
||||||
// disable the add form if address helper is disabled
|
try {
|
||||||
if(internalPath.equals("/add") &&
|
// disable the add form if address helper is disabled
|
||||||
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
|
if(internalPath.equals("/add") &&
|
||||||
out.write(ERR_HELPER_DISABLED);
|
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
|
||||||
} else {
|
out.write(ERR_HELPER_DISABLED.getBytes("UTF-8"));
|
||||||
LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce);
|
} else {
|
||||||
|
LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce);
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
}
|
}
|
||||||
s.close();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,7 +1020,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
byte[] response;
|
byte[] response;
|
||||||
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
|
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
|
||||||
data = null;
|
data = null;
|
||||||
response = SUCCESS_RESPONSE;
|
response = SUCCESS_RESPONSE.getBytes("UTF-8");
|
||||||
} else {
|
} else {
|
||||||
data = newRequest.toString().getBytes("ISO-8859-1");
|
data = newRequest.toString().getBytes("ISO-8859-1");
|
||||||
response = null;
|
response = null;
|
||||||
@@ -993,9 +1046,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(_log.shouldLog(Log.WARN)) {
|
if(_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn(getPrefix(requestId) + "Could not find destination for " + addressHelper);
|
_log.warn(getPrefix(requestId) + "Could not find destination for " + addressHelper);
|
||||||
}
|
}
|
||||||
byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
|
String header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
|
||||||
writeErrorMessage(header, out, targetRequest, false, destination);
|
try {
|
||||||
s.close();
|
writeErrorMessage(header, out, targetRequest, false, destination);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if("i2p".equals(host)) {
|
} else if("i2p".equals(host)) {
|
||||||
@@ -1025,7 +1083,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(_log.shouldLog(Log.WARN)) {
|
if(_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest);
|
_log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest);
|
||||||
}
|
}
|
||||||
byte[] header;
|
String header;
|
||||||
String jumpServers = null;
|
String jumpServers = null;
|
||||||
String extraMessage = null;
|
String extraMessage = null;
|
||||||
if(usingWWWProxy) {
|
if(usingWWWProxy) {
|
||||||
@@ -1042,16 +1100,26 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
jumpServers = DEFAULT_JUMP_SERVERS;
|
jumpServers = DEFAULT_JUMP_SERVERS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeErrorMessage(header, extraMessage, out, targetRequest, usingWWWProxy, destination, jumpServers);
|
try {
|
||||||
s.close();
|
writeErrorMessage(header, extraMessage, out, targetRequest, usingWWWProxy, destination, jumpServers);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.toUpperCase(Locale.US).equals("CONNECT") &&
|
if (method.toUpperCase(Locale.US).equals("CONNECT") &&
|
||||||
!usingWWWProxy &&
|
!usingWWWProxy &&
|
||||||
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_INTERNAL_SSL))) {
|
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_INTERNAL_SSL))) {
|
||||||
writeErrorMessage(ERR_INTERNAL_SSL, out, targetRequest, false, destination);
|
try {
|
||||||
s.close();
|
writeErrorMessage(ERR_INTERNAL_SSL, out, targetRequest, false, destination);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("SSL to i2p destinations denied by configuration: " + targetRequest);
|
_log.warn("SSL to i2p destinations denied by configuration: " + targetRequest);
|
||||||
return;
|
return;
|
||||||
@@ -1063,8 +1131,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(ahelperNew && "GET".equals(method) &&
|
if(ahelperNew && "GET".equals(method) &&
|
||||||
(userAgent == null || !userAgent.startsWith("Wget")) &&
|
(userAgent == null || !userAgent.startsWith("Wget")) &&
|
||||||
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
|
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
|
||||||
writeHelperSaveForm(out, destination, ahelperKey, targetRequest, referer);
|
try {
|
||||||
s.close();
|
writeHelperSaveForm(out, destination, ahelperKey, targetRequest, referer);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1077,10 +1150,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
if(_log.shouldLog(Log.DEBUG)) {
|
if(_log.shouldLog(Log.DEBUG)) {
|
||||||
_log.debug("Auto redirecting to " + uri);
|
_log.debug("Auto redirecting to " + uri);
|
||||||
}
|
}
|
||||||
out.write(("HTTP/1.1 301 Address Helper Accepted\r\n" +
|
try {
|
||||||
|
out.write(("HTTP/1.1 301 Address Helper Accepted\r\n" +
|
||||||
"Location: " + uri + "\r\n" +
|
"Location: " + uri + "\r\n" +
|
||||||
"\r\n").getBytes("UTF-8"));
|
"\r\n").getBytes("UTF-8"));
|
||||||
s.close();
|
} catch (IOException ioe) {
|
||||||
|
// ignore
|
||||||
|
} finally {
|
||||||
|
closeSocket(s);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1103,7 +1181,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
response = null;
|
response = null;
|
||||||
} else {
|
} else {
|
||||||
data = null;
|
data = null;
|
||||||
response = SUCCESS_RESPONSE;
|
response = SUCCESS_RESPONSE.getBytes("UTF-8");
|
||||||
}
|
}
|
||||||
t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
|
t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
|
||||||
} else {
|
} else {
|
||||||
@@ -1157,22 +1235,22 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @since 0.8.7 */
|
/** @since 0.8.7 */
|
||||||
private void writeHelperSaveForm(OutputStream out, String destination, String ahelperKey,
|
private void writeHelperSaveForm(OutputStream outs, String destination, String ahelperKey,
|
||||||
String targetRequest, String referer) throws IOException {
|
String targetRequest, String referer) throws IOException {
|
||||||
if(out == null) {
|
if(outs == null)
|
||||||
return;
|
return;
|
||||||
}
|
Writer out = new BufferedWriter(new OutputStreamWriter(outs, "UTF-8"));
|
||||||
byte[] header = getErrorPage("ahelper-new", ERR_AHELPER_NEW);
|
String header = getErrorPage("ahelper-new", ERR_AHELPER_NEW);
|
||||||
out.write(header);
|
out.write(header);
|
||||||
out.write(("<table><tr><td class=\"mediumtags\" align=\"right\">" + _("Host") +
|
out.write("<table><tr><td class=\"mediumtags\" align=\"right\">" + _("Host") +
|
||||||
"</td><td class=\"mediumtags\">" + destination + "</td></tr>\n").getBytes());
|
"</td><td class=\"mediumtags\">" + destination + "</td></tr>\n");
|
||||||
try {
|
try {
|
||||||
String b32 = Base32.encode(SHA256Generator.getInstance().calculateHash(Base64.decode(ahelperKey)).getData());
|
String b32 = Base32.encode(SHA256Generator.getInstance().calculateHash(Base64.decode(ahelperKey)).getData());
|
||||||
out.write(("<tr><td class=\"mediumtags\" align=\"right\">" + _("Base 32") + "</td>" +
|
out.write("<tr><td class=\"mediumtags\" align=\"right\">" + _("Base 32") + "</td>" +
|
||||||
"<td><a href=\"http://" + b32 + ".b32.i2p/\">" + b32 + ".b32.i2p</a></td></tr>").getBytes());
|
"<td><a href=\"http://" + b32 + ".b32.i2p/\">" + b32 + ".b32.i2p</a></td></tr>");
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
}
|
}
|
||||||
out.write(("<tr><td class=\"mediumtags\" align=\"right\">" + _("Destination") + "</td><td>" +
|
out.write("<tr><td class=\"mediumtags\" align=\"right\">" + _("Destination") + "</td><td>" +
|
||||||
"<textarea rows=\"1\" style=\"height: 4em; min-width: 0; min-height: 0;\" cols=\"70\" wrap=\"off\" readonly=\"readonly\" >" +
|
"<textarea rows=\"1\" style=\"height: 4em; min-width: 0; min-height: 0;\" cols=\"70\" wrap=\"off\" readonly=\"readonly\" >" +
|
||||||
ahelperKey + "</textarea></td></tr></table>\n" +
|
ahelperKey + "</textarea></td></tr></table>\n" +
|
||||||
"<hr><div class=\"formaction\">" +
|
"<hr><div class=\"formaction\">" +
|
||||||
@@ -1183,18 +1261,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
"<input type=\"hidden\" name=\"host\" value=\"" + destination + "\">\n" +
|
"<input type=\"hidden\" name=\"host\" value=\"" + destination + "\">\n" +
|
||||||
"<input type=\"hidden\" name=\"dest\" value=\"" + ahelperKey + "\">\n" +
|
"<input type=\"hidden\" name=\"dest\" value=\"" + ahelperKey + "\">\n" +
|
||||||
"<input type=\"hidden\" name=\"nonce\" value=\"" + _proxyNonce + "\">\n" +
|
"<input type=\"hidden\" name=\"nonce\" value=\"" + _proxyNonce + "\">\n" +
|
||||||
"<button type=\"submit\" class=\"accept\" name=\"router\" value=\"router\">" + _("Save {0} to router address book and continue to website", destination) + "</button><br>\n").getBytes("UTF-8"));
|
"<button type=\"submit\" class=\"accept\" name=\"router\" value=\"router\">" +
|
||||||
|
_("Save {0} to router address book and continue to website", destination) + "</button><br>\n");
|
||||||
if(_context.namingService().getName().equals("BlockfileNamingService")) {
|
if(_context.namingService().getName().equals("BlockfileNamingService")) {
|
||||||
// only blockfile supports multiple books
|
// only blockfile supports multiple books
|
||||||
out.write(("<br><button type=\"submit\" name=\"master\" value=\"master\">" + _("Save {0} to master address book and continue to website", destination) + "</button><br>\n").getBytes("UTF-8"));
|
out.write("<br><button type=\"submit\" name=\"master\" value=\"master\">" + _("Save {0} to master address book and continue to website", destination) + "</button><br>\n");
|
||||||
out.write(("<button type=\"submit\" name=\"private\" value=\"private\">" + _("Save {0} to private address book and continue to website", destination) + "</button>\n").getBytes("UTF-8"));
|
out.write("<button type=\"submit\" name=\"private\" value=\"private\">" + _("Save {0} to private address book and continue to website", destination) + "</button>\n");
|
||||||
}
|
}
|
||||||
// Firefox (and others?) don't send referer to meta refresh target, which is
|
// Firefox (and others?) don't send referer to meta refresh target, which is
|
||||||
// what the jump servers use, so this isn't that useful.
|
// what the jump servers use, so this isn't that useful.
|
||||||
if (referer != null)
|
if (referer != null)
|
||||||
out.write(("<input type=\"hidden\" name=\"referer\" value=\"" + referer + "\">\n").getBytes("UTF-8"));
|
out.write("<input type=\"hidden\" name=\"referer\" value=\"" + referer + "\">\n");
|
||||||
out.write(("<input type=\"hidden\" name=\"url\" value=\"" + targetRequest + "\">\n" +
|
out.write("<input type=\"hidden\" name=\"url\" value=\"" + targetRequest + "\">\n" +
|
||||||
"</form></div></div>").getBytes());
|
"</form></div></div>");
|
||||||
writeFooter(out);
|
writeFooter(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1296,11 +1375,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
|||||||
return lc.equals("http") || lc.equals("https");
|
return lc.equals("http") || lc.equals("https");
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static byte[] ERR_HELPER_DISABLED =
|
private final static String ERR_HELPER_DISABLED =
|
||||||
("HTTP/1.1 403 Disabled\r\n" +
|
"HTTP/1.1 403 Disabled\r\n" +
|
||||||
"Content-Type: text/plain\r\n" +
|
"Content-Type: text/plain\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
"Address helpers disabled").getBytes();
|
"Address helpers disabled";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change various parts of the URI.
|
* Change various parts of the URI.
|
||||||
|
@@ -3,12 +3,15 @@
|
|||||||
*/
|
*/
|
||||||
package net.i2p.i2ptunnel;
|
package net.i2p.i2ptunnel;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.io.Writer;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
@@ -71,18 +74,17 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
|
|
||||||
protected final List<String> _proxyList;
|
protected final List<String> _proxyList;
|
||||||
|
|
||||||
protected final static byte[] ERR_NO_OUTPROXY =
|
protected final static String ERR_NO_OUTPROXY =
|
||||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
"HTTP/1.1 503 Service Unavailable\r\n"+
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||||
"Cache-control: no-cache\r\n"+
|
"Cache-control: no-cache\r\n"+
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
"<html><body><H1>I2P ERROR: No outproxy found</H1>"+
|
"<html><body><H1>I2P ERROR: No outproxy found</H1>"+
|
||||||
"Your request was for a site outside of I2P, but you have no "+
|
"Your request was for a site outside of I2P, but you have no "+
|
||||||
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel")
|
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel";
|
||||||
.getBytes();
|
|
||||||
|
|
||||||
protected final static byte[] ERR_DESTINATION_UNKNOWN =
|
protected final static String ERR_DESTINATION_UNKNOWN =
|
||||||
("HTTP/1.1 503 Service Unavailable\r\n" +
|
"HTTP/1.1 503 Service Unavailable\r\n" +
|
||||||
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
"Content-Type: text/html; charset=iso-8859-1\r\n" +
|
||||||
"Cache-control: no-cache\r\n" +
|
"Cache-control: no-cache\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
@@ -91,13 +93,12 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
"wrong BASE64 I2P Destination or the link you are following is " +
|
"wrong BASE64 I2P Destination or the link you are following is " +
|
||||||
"bad. The host (or the WWW proxy, if you're using one) could also " +
|
"bad. The host (or the WWW proxy, if you're using one) could also " +
|
||||||
"be temporarily offline. You may want to <b>retry</b>. " +
|
"be temporarily offline. You may want to <b>retry</b>. " +
|
||||||
"Could not find the following Destination:<BR><BR><div>").getBytes();
|
"Could not find the following Destination:<BR><BR><div>";
|
||||||
|
|
||||||
protected final static byte[] SUCCESS_RESPONSE =
|
protected final static String SUCCESS_RESPONSE =
|
||||||
("HTTP/1.1 200 Connection Established\r\n"+
|
"HTTP/1.1 200 Connection Established\r\n"+
|
||||||
"Proxy-agent: I2P\r\n"+
|
"Proxy-agent: I2P\r\n"+
|
||||||
"\r\n")
|
"\r\n";
|
||||||
.getBytes();
|
|
||||||
|
|
||||||
private final byte[] _proxyNonce;
|
private final byte[] _proxyNonce;
|
||||||
private final ConcurrentHashMap<String, NonceInfo> _nonces;
|
private final ConcurrentHashMap<String, NonceInfo> _nonces;
|
||||||
@@ -484,7 +485,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* @return non-null
|
* @return non-null
|
||||||
* @since 0.9.4 moved from I2PTunnelHTTPClient
|
* @since 0.9.4 moved from I2PTunnelHTTPClient
|
||||||
*/
|
*/
|
||||||
protected byte[] getErrorPage(String base, byte[] backup) {
|
protected String getErrorPage(String base, String backup) {
|
||||||
return getErrorPage(_context, base, backup);
|
return getErrorPage(_context, base, backup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,7 +500,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* @return non-null
|
* @return non-null
|
||||||
* @since 0.9.4 moved from I2PTunnelHTTPClient
|
* @since 0.9.4 moved from I2PTunnelHTTPClient
|
||||||
*/
|
*/
|
||||||
protected static byte[] getErrorPage(I2PAppContext ctx, String base, byte[] backup) {
|
protected static String getErrorPage(I2PAppContext ctx, String base, String backup) {
|
||||||
File errorDir = new File(ctx.getBaseDir(), "docs");
|
File errorDir = new File(ctx.getBaseDir(), "docs");
|
||||||
File file = new File(errorDir, base + "-header.ht");
|
File file = new File(errorDir, base + "-header.ht");
|
||||||
try {
|
try {
|
||||||
@@ -515,7 +516,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
/**
|
/**
|
||||||
* @since 0.9.4 moved from I2PTunnelHTTPClient
|
* @since 0.9.4 moved from I2PTunnelHTTPClient
|
||||||
*/
|
*/
|
||||||
private static byte[] readFile(I2PAppContext ctx, File file) throws IOException {
|
private static String readFile(I2PAppContext ctx, File file) throws IOException {
|
||||||
Reader reader = null;
|
Reader reader = null;
|
||||||
char[] buf = new char[512];
|
char[] buf = new char[512];
|
||||||
StringBuilder out = new StringBuilder(2048);
|
StringBuilder out = new StringBuilder(2048);
|
||||||
@@ -525,7 +526,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
while((len = reader.read(buf)) > 0) {
|
while((len = reader.read(buf)) > 0) {
|
||||||
out.append(buf, 0, len);
|
out.append(buf, 0, len);
|
||||||
}
|
}
|
||||||
return out.toString().getBytes("UTF-8");
|
return out.toString();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if(reader != null)
|
if(reader != null)
|
||||||
@@ -578,7 +579,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
boolean usingWWWProxy, String wwwProxy, long requestId) {
|
boolean usingWWWProxy, String wwwProxy, long requestId) {
|
||||||
if (out == null)
|
if (out == null)
|
||||||
return;
|
return;
|
||||||
byte[] header;
|
String header;
|
||||||
if (usingWWWProxy)
|
if (usingWWWProxy)
|
||||||
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN);
|
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN);
|
||||||
else
|
else
|
||||||
@@ -612,7 +613,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
} else {
|
} else {
|
||||||
error = usingWWWProxy ? "dnfp" : "dnf";
|
error = usingWWWProxy ? "dnfp" : "dnf";
|
||||||
}
|
}
|
||||||
byte[] header = getErrorPage(error, ERR_DESTINATION_UNKNOWN);
|
String header = getErrorPage(error, ERR_DESTINATION_UNKNOWN);
|
||||||
String message = ise != null ? ise.getLocalizedMessage() : "unknown error";
|
String message = ise != null ? ise.getLocalizedMessage() : "unknown error";
|
||||||
try {
|
try {
|
||||||
writeErrorMessage(header, message, out, targetRequest, usingWWWProxy, wwwProxy);
|
writeErrorMessage(header, message, out, targetRequest, usingWWWProxy, wwwProxy);
|
||||||
@@ -623,7 +624,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* No jump servers or extra message
|
* No jump servers or extra message
|
||||||
* @since 0.9.14
|
* @since 0.9.14
|
||||||
*/
|
*/
|
||||||
protected void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
|
protected void writeErrorMessage(String errMessage, OutputStream out, String targetRequest,
|
||||||
boolean usingWWWProxy, String wwwProxy) throws IOException {
|
boolean usingWWWProxy, String wwwProxy) throws IOException {
|
||||||
writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, null);
|
writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, null);
|
||||||
}
|
}
|
||||||
@@ -633,7 +634,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* @param jumpServers comma- or space-separated list, or null
|
* @param jumpServers comma- or space-separated list, or null
|
||||||
* @since 0.9.14 moved from subclasses
|
* @since 0.9.14 moved from subclasses
|
||||||
*/
|
*/
|
||||||
protected void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
|
protected void writeErrorMessage(String errMessage, OutputStream out, String targetRequest,
|
||||||
boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException {
|
boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException {
|
||||||
writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, jumpServers);
|
writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, jumpServers);
|
||||||
}
|
}
|
||||||
@@ -643,7 +644,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* @param extraMessage extra message or null, will be HTML-escaped
|
* @param extraMessage extra message or null, will be HTML-escaped
|
||||||
* @since 0.9.14
|
* @since 0.9.14
|
||||||
*/
|
*/
|
||||||
protected void writeErrorMessage(byte[] errMessage, String extraMessage,
|
protected void writeErrorMessage(String errMessage, String extraMessage,
|
||||||
OutputStream out, String targetRequest,
|
OutputStream out, String targetRequest,
|
||||||
boolean usingWWWProxy, String wwwProxy) throws IOException {
|
boolean usingWWWProxy, String wwwProxy) throws IOException {
|
||||||
writeErrorMessage(errMessage, extraMessage, out, targetRequest, usingWWWProxy, wwwProxy, null);
|
writeErrorMessage(errMessage, extraMessage, out, targetRequest, usingWWWProxy, wwwProxy, null);
|
||||||
@@ -654,27 +655,28 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* @param extraMessage extra message or null, will be HTML-escaped
|
* @param extraMessage extra message or null, will be HTML-escaped
|
||||||
* @since 0.9.14
|
* @since 0.9.14
|
||||||
*/
|
*/
|
||||||
protected void writeErrorMessage(byte[] errMessage, String extraMessage,
|
protected void writeErrorMessage(String errMessage, String extraMessage,
|
||||||
OutputStream out, String targetRequest,
|
OutputStream outs, String targetRequest,
|
||||||
boolean usingWWWProxy, String wwwProxy,
|
boolean usingWWWProxy, String wwwProxy,
|
||||||
String jumpServers) throws IOException {
|
String jumpServers) throws IOException {
|
||||||
if (out == null)
|
if (outs == null)
|
||||||
return;
|
return;
|
||||||
|
Writer out = new BufferedWriter(new OutputStreamWriter(outs, "UTF-8"));
|
||||||
out.write(errMessage);
|
out.write(errMessage);
|
||||||
if (targetRequest != null) {
|
if (targetRequest != null) {
|
||||||
String uri = targetRequest.replace("&", "&");
|
String uri = targetRequest.replace("&", "&");
|
||||||
out.write("<a href=\"".getBytes());
|
out.write("<a href=\"");
|
||||||
out.write(uri.getBytes());
|
out.write(uri);
|
||||||
out.write("\">".getBytes());
|
out.write("\">");
|
||||||
out.write(uri.getBytes());
|
out.write(uri);
|
||||||
out.write("</a>".getBytes());
|
out.write("</a>");
|
||||||
if (usingWWWProxy) {
|
if (usingWWWProxy) {
|
||||||
out.write(("<br><br><b>").getBytes());
|
out.write("<br><br><b>");
|
||||||
out.write(_("HTTP Outproxy").getBytes("UTF-8"));
|
out.write(_("HTTP Outproxy"));
|
||||||
out.write((":</b> " + wwwProxy).getBytes());
|
out.write(":</b> " + wwwProxy);
|
||||||
}
|
}
|
||||||
if (extraMessage != null) {
|
if (extraMessage != null) {
|
||||||
out.write(("<br><br><b>" + DataHelper.escapeHTML(extraMessage) + "</b>").getBytes());
|
out.write("<br><br><b>" + DataHelper.escapeHTML(extraMessage) + "</b>");
|
||||||
}
|
}
|
||||||
if (jumpServers != null && jumpServers.length() > 0) {
|
if (jumpServers != null && jumpServers.length() > 0) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
@@ -708,23 +710,23 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
out.write("<br><br><h3>".getBytes());
|
out.write("<br><br><h3>");
|
||||||
out.write(_("Click a link below for an address helper from a jump service").getBytes("UTF-8"));
|
out.write(_("Click a link below for an address helper from a jump service"));
|
||||||
out.write("</h3>\n".getBytes());
|
out.write("</h3>\n");
|
||||||
} else {
|
} else {
|
||||||
out.write("<br>".getBytes());
|
out.write("<br>");
|
||||||
}
|
}
|
||||||
out.write("<a href=\"".getBytes());
|
out.write("<a href=\"");
|
||||||
out.write(jurl.getBytes());
|
out.write(jurl);
|
||||||
out.write(uri.getBytes());
|
out.write(uri);
|
||||||
out.write("\">".getBytes());
|
out.write("\">");
|
||||||
// Translators: parameter is a host name
|
// Translators: parameter is a host name
|
||||||
out.write(_("{0} jump service", jumphost).getBytes());
|
out.write(_("{0} jump service", jumphost));
|
||||||
out.write("</a>\n".getBytes());
|
out.write("</a>\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.write("</div>".getBytes());
|
out.write("</div>");
|
||||||
writeFooter(out);
|
writeFooter(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,12 +737,29 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
* @since 0.9.14 moved from I2PTunnelHTTPClient
|
* @since 0.9.14 moved from I2PTunnelHTTPClient
|
||||||
*/
|
*/
|
||||||
public static void writeFooter(OutputStream out) throws IOException {
|
public static void writeFooter(OutputStream out) throws IOException {
|
||||||
|
out.write(getFooter().getBytes("UTF-8"));
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes.
|
||||||
|
*
|
||||||
|
* Public only for LocalHTTPServer, not for general use
|
||||||
|
* @since 0.9.19
|
||||||
|
*/
|
||||||
|
public static void writeFooter(Writer out) throws IOException {
|
||||||
|
out.write(getFooter());
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFooter() {
|
||||||
// The css is hiding this div for now, but we'll keep it here anyway
|
// The css is hiding this div for now, but we'll keep it here anyway
|
||||||
// Tag the strings below for translation if we unhide it.
|
// Tag the strings below for translation if we unhide it.
|
||||||
out.write("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
StringBuilder buf = new StringBuilder(128);
|
||||||
out.write(new Date().toString().getBytes());
|
buf.append("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ")
|
||||||
out.write("</i></div></body></html>\n".getBytes());
|
.append(new Date().toString())
|
||||||
out.flush();
|
.append("</i></div></body></html>\n");
|
||||||
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -327,7 +327,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
|||||||
|
|
||||||
long afterHandle = getTunnel().getContext().clock().now();
|
long afterHandle = getTunnel().getContext().clock().now();
|
||||||
long timeToHandle = afterHandle - afterAccept;
|
long timeToHandle = afterHandle - afterAccept;
|
||||||
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
|
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle);
|
||||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||||
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
||||||
" [" + timeToHandle +
|
" [" + timeToHandle +
|
||||||
@@ -696,7 +696,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (trimmed > 0)
|
if (trimmed > 0)
|
||||||
ctx.statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed, 0);
|
ctx.statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@@ -983,7 +983,7 @@ public class TunnelController implements Logging {
|
|||||||
* @return list of messages pulled off (each is a String, earliest first)
|
* @return list of messages pulled off (each is a String, earliest first)
|
||||||
*/
|
*/
|
||||||
public List<String> clearMessages() {
|
public List<String> clearMessages() {
|
||||||
List<String> rv = null;
|
List<String> rv;
|
||||||
synchronized (_messages) {
|
synchronized (_messages) {
|
||||||
rv = new ArrayList<String>(_messages);
|
rv = new ArrayList<String>(_messages);
|
||||||
_messages.clear();
|
_messages.clear();
|
||||||
|
@@ -33,19 +33,17 @@ import net.i2p.util.Translate;
|
|||||||
*/
|
*/
|
||||||
public abstract class LocalHTTPServer {
|
public abstract class LocalHTTPServer {
|
||||||
|
|
||||||
private final static byte[] ERR_404 =
|
private final static String ERR_404 =
|
||||||
("HTTP/1.1 404 Not Found\r\n"+
|
"HTTP/1.1 404 Not Found\r\n"+
|
||||||
"Content-Type: text/plain\r\n"+
|
"Content-Type: text/plain\r\n"+
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
"HTTP Proxy local file not found")
|
"HTTP Proxy local file not found";
|
||||||
.getBytes();
|
|
||||||
|
|
||||||
private final static byte[] ERR_ADD =
|
private final static String ERR_ADD =
|
||||||
("HTTP/1.1 409 Bad\r\n"+
|
"HTTP/1.1 409 Bad\r\n"+
|
||||||
"Content-Type: text/plain\r\n"+
|
"Content-Type: text/plain\r\n"+
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
"Add to addressbook failed - bad parameters")
|
"Add to addressbook failed - bad parameters";
|
||||||
.getBytes();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Very simple web server.
|
* Very simple web server.
|
||||||
@@ -69,14 +67,13 @@ public abstract class LocalHTTPServer {
|
|||||||
* @param targetRequest decoded path only, non-null
|
* @param targetRequest decoded path only, non-null
|
||||||
* @param query raw (encoded), may be null
|
* @param query raw (encoded), may be null
|
||||||
*/
|
*/
|
||||||
public static void serveLocalFile(OutputStream out, String method, String targetRequest, String query, String proxyNonce) {
|
public static void serveLocalFile(OutputStream out, String method, String targetRequest,
|
||||||
|
String query, String proxyNonce) throws IOException {
|
||||||
//System.err.println("targetRequest: \"" + targetRequest + "\"");
|
//System.err.println("targetRequest: \"" + targetRequest + "\"");
|
||||||
// a home page message for the curious...
|
// a home page message for the curious...
|
||||||
if (targetRequest.equals("/")) {
|
if (targetRequest.equals("/")) {
|
||||||
try {
|
out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes("UTF-8"));
|
||||||
out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes());
|
out.flush();
|
||||||
out.flush();
|
|
||||||
} catch (IOException ioe) {}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((method.equals("GET") || method.equals("HEAD")) &&
|
if ((method.equals("GET") || method.equals("HEAD")) &&
|
||||||
@@ -104,12 +101,10 @@ public abstract class LocalHTTPServer {
|
|||||||
else if (filename.endsWith(".jpg"))
|
else if (filename.endsWith(".jpg"))
|
||||||
type = "image/jpeg";
|
type = "image/jpeg";
|
||||||
else type = "text/html";
|
else type = "text/html";
|
||||||
try {
|
out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes("UTF-8"));
|
||||||
out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes());
|
out.write(type.getBytes("UTF-8"));
|
||||||
out.write(type.getBytes());
|
out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes("UTF-8"));
|
||||||
out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes());
|
FileUtil.readFile(filename, themesDir.getAbsolutePath(), out);
|
||||||
FileUtil.readFile(filename, themesDir.getAbsolutePath(), out);
|
|
||||||
} catch (IOException ioe) {}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,31 +148,24 @@ public abstract class LocalHTTPServer {
|
|||||||
//System.err.println("book : \"" + book + "\"");
|
//System.err.println("book : \"" + book + "\"");
|
||||||
//System.err.println("nonce : \"" + nonce + "\"");
|
//System.err.println("nonce : \"" + nonce + "\"");
|
||||||
if (proxyNonce.equals(nonce) && url != null && host != null && dest != null) {
|
if (proxyNonce.equals(nonce) && url != null && host != null && dest != null) {
|
||||||
try {
|
NamingService ns = I2PAppContext.getGlobalContext().namingService();
|
||||||
NamingService ns = I2PAppContext.getGlobalContext().namingService();
|
Properties nsOptions = new Properties();
|
||||||
Properties nsOptions = new Properties();
|
nsOptions.setProperty("list", book);
|
||||||
nsOptions.setProperty("list", book);
|
if (referer != null && referer.startsWith("http")) {
|
||||||
if (referer != null && referer.startsWith("http")) {
|
String from = "<a href=\"" + referer + "\">" + referer + "</a>";
|
||||||
String from = "<a href=\"" + referer + "\">" + referer + "</a>";
|
nsOptions.setProperty("s", _("Added via address helper from {0}", from));
|
||||||
nsOptions.setProperty("s", _("Added via address helper from {0}", from));
|
} else {
|
||||||
} else {
|
nsOptions.setProperty("s", _("Added via address helper"));
|
||||||
nsOptions.setProperty("s", _("Added via address helper"));
|
}
|
||||||
}
|
boolean success = ns.put(host, dest, nsOptions);
|
||||||
boolean success = ns.put(host, dest, nsOptions);
|
writeRedirectPage(out, success, host, book, url);
|
||||||
writeRedirectPage(out, success, host, book, url);
|
return;
|
||||||
return;
|
|
||||||
} catch (IOException ioe) {}
|
|
||||||
}
|
}
|
||||||
try {
|
out.write(ERR_ADD.getBytes("UTF-8"));
|
||||||
out.write(ERR_ADD);
|
} else {
|
||||||
out.flush();
|
out.write(ERR_404.getBytes("UTF-8"));
|
||||||
} catch (IOException ioe) {}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
out.flush();
|
||||||
out.write(ERR_404);
|
|
||||||
out.flush();
|
|
||||||
} catch (IOException ioe) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 0.8.7 */
|
/** @since 0.8.7 */
|
||||||
|
Reference in New Issue
Block a user