mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-27 12:40:47 +00:00
JPProxy update
This commit is contained in:
@@ -3,11 +3,6 @@ package com.jpexs.proxy;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Class used to represent an array of bytes as an Object.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class ByteArray {
|
||||
public byte bytes[];
|
||||
public int offset = 0;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
public interface Cleanable
|
||||
{
|
||||
public void clean();
|
||||
}
|
||||
@@ -1,25 +1,19 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Client which reads a Request and writes a Reply.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class Client extends Connection {
|
||||
public class Client extends Connection
|
||||
{
|
||||
/**
|
||||
* Create a Client from a Socket.
|
||||
*/
|
||||
Client(Socket s) throws IOException {
|
||||
super(s);
|
||||
in = new BufferedInputStream(in);
|
||||
//out = new DebugOutputStream(new BufferedOutputStream(out));
|
||||
out = new BufferedOutputStream(out);
|
||||
Client(Socket s) throws IOException
|
||||
{
|
||||
super(s);
|
||||
in = new BufferedInputStream(in);
|
||||
//out = new DebugOutputStream(new BufferedOutputStream(out));
|
||||
out = new BufferedOutputStream(out);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,17 +21,22 @@ public class Client extends Connection {
|
||||
* Read a Request.
|
||||
*
|
||||
* @returns a Request.
|
||||
* @see Request
|
||||
*/
|
||||
Request read() throws IOException {
|
||||
Request request = new Request(this);
|
||||
request.read(getInputStream());
|
||||
return request;
|
||||
Request read() throws IOException
|
||||
{
|
||||
Request request = new Request(this);
|
||||
request.read(getInputStream());
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a Reply
|
||||
*
|
||||
* @see Reply
|
||||
*/
|
||||
void write(Reply reply) throws IOException {
|
||||
reply.write(getOutputStream());
|
||||
void write(Reply reply) throws IOException
|
||||
{
|
||||
reply.write(getOutputStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,28 +6,25 @@ import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
|
||||
/**
|
||||
* Create a TCP connection from a Socket or hostname/port
|
||||
* with buffered IO.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
* @see java.net.Socket
|
||||
*/
|
||||
class Connection {
|
||||
class Connection
|
||||
{
|
||||
Socket socket = null;
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
|
||||
/**
|
||||
* Create a Connection from a Socket.
|
||||
*
|
||||
* @param socket a socket
|
||||
*/
|
||||
Connection(Socket socket) throws IOException {
|
||||
this.socket = socket;
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
Connection(Socket socket) throws IOException
|
||||
{
|
||||
this.socket = socket;
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,67 +33,82 @@ class Connection {
|
||||
* @param host remote hostname
|
||||
* @param port remote port
|
||||
*/
|
||||
Connection(String host, int port) throws IOException {
|
||||
this(new Socket(host, port));
|
||||
Connection(String host, int port) throws IOException
|
||||
{
|
||||
this(new Socket(InetAddress.getByName(host), port));
|
||||
}
|
||||
|
||||
Connection() {
|
||||
Connection()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input stream.
|
||||
*/
|
||||
InputStream getInputStream() {
|
||||
return in;
|
||||
InputStream getInputStream()
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the output stream.
|
||||
*/
|
||||
OutputStream getOutputStream() {
|
||||
return out;
|
||||
OutputStream getOutputStream()
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
void setInputStream(InputStream in) {
|
||||
this.in = in;
|
||||
void setInputStream(InputStream in)
|
||||
{
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
void setOutputStream(OutputStream out) {
|
||||
this.out = out;
|
||||
|
||||
void setOutputStream(OutputStream out)
|
||||
{
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*/
|
||||
void close() {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.out.println("Connection: " + e);
|
||||
}
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.out.println("Connection: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Socket getSocket() {
|
||||
return socket;
|
||||
public Socket getSocket()
|
||||
{
|
||||
return socket;
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
return socket.getInetAddress();
|
||||
public InetAddress getInetAddress()
|
||||
{
|
||||
return socket.getInetAddress();
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return socket.getPort();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return socket.getPort();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getInetAddress().getHostAddress() + ":" + getPort();
|
||||
public String toString()
|
||||
{
|
||||
return getInetAddress().getHostAddress() + ":" + getPort();
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout)
|
||||
throws SocketException {
|
||||
socket.setSoTimeout(timeout);
|
||||
throws SocketException
|
||||
{
|
||||
socket.setSoTimeout(timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,39 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
|
||||
class Copy implements Runnable {
|
||||
class Copy implements Runnable
|
||||
{
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
Copy(InputStream in, OutputStream out) {
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
|
||||
Copy(InputStream in, OutputStream out)
|
||||
{
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
public void run()
|
||||
{
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
|
||||
try {
|
||||
while ((n = in.read(buffer, 0, buffer.length)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
out.flush();
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
String s = e.toString();
|
||||
// ignore socket closed exceptions
|
||||
if (s.toLowerCase().indexOf("socket closed") == -1) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
while ((n = in.read(buffer, 0, buffer.length)) > 0)
|
||||
{
|
||||
out.write(buffer, 0, n);
|
||||
out.flush();
|
||||
}
|
||||
out.flush();
|
||||
}catch(SocketException e){
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//Ignore errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,21 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
class Http extends HttpConnection {
|
||||
class Http extends HttpConnection
|
||||
{
|
||||
static final boolean DEBUG = false; /* enable lots of debug output */
|
||||
|
||||
/* XXX - more than 1 should work now. */
|
||||
static final int MAX_PENDING_REQUESTS = 1;
|
||||
|
||||
|
||||
static Hashtable cache = new Hashtable(33);
|
||||
private static Object httpLock = new Object();
|
||||
|
||||
|
||||
|
||||
String host;
|
||||
int port;
|
||||
@@ -27,270 +25,342 @@ class Http extends HttpConnection {
|
||||
long idle = 0;
|
||||
Vector queue = new Vector();
|
||||
|
||||
Http(String host, int port) throws IOException {
|
||||
this(host, port, false);
|
||||
Http(String host, int port) throws IOException
|
||||
{
|
||||
this(host, port, false);
|
||||
}
|
||||
|
||||
Http(String host, int port, boolean isProxy) throws IOException
|
||||
{
|
||||
super(host, port);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.proxy = isProxy;
|
||||
}
|
||||
|
||||
Http(String host, int port, boolean isProxy) throws IOException {
|
||||
super(host, port);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.proxy = isProxy;
|
||||
Http(String host, int port, boolean isProxy,Socket sock) throws IOException
|
||||
{
|
||||
super(sock);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.proxy = isProxy;
|
||||
}
|
||||
|
||||
public synchronized void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
queue.addElement(request);
|
||||
|
||||
try {
|
||||
send(request);
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (persistent) {
|
||||
persistent = false;
|
||||
if (DEBUG) System.out.println("RETRY SEND " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
throws IOException, RetryRequestException
|
||||
{
|
||||
queue.addElement(request);
|
||||
|
||||
try
|
||||
{
|
||||
send(request);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (persistent)
|
||||
{
|
||||
persistent = false;
|
||||
if (DEBUG) System.out.println("RETRY SEND " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Reply recvReply(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
while (queue.firstElement() != request) {
|
||||
try {
|
||||
wait();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
throws IOException, RetryRequestException
|
||||
{
|
||||
while (queue.firstElement() != request)
|
||||
{
|
||||
try
|
||||
{
|
||||
wait();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (closed) {
|
||||
if (DEBUG) System.out.println("RETRY CLOSED " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
if (closed)
|
||||
{
|
||||
if (DEBUG) System.out.println("RETRY CLOSED " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
|
||||
try {
|
||||
return recv();
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (persistent) {
|
||||
persistent = false;
|
||||
if (DEBUG) System.out.println("RETRY RECV " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
try
|
||||
{
|
||||
return recv();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (persistent)
|
||||
{
|
||||
persistent = false;
|
||||
if (DEBUG) System.out.println("RETRY RECV " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public void reallyClose() {
|
||||
persistent = false;
|
||||
if (DEBUG)
|
||||
System.out.println("REALLY CLOSE " + this);
|
||||
close();
|
||||
public void reallyClose()
|
||||
{
|
||||
persistent = false;
|
||||
if (DEBUG)
|
||||
System.out.println("REALLY CLOSE " + this);
|
||||
close();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
if (persistent) {
|
||||
idle = System.currentTimeMillis();
|
||||
} else {
|
||||
cacheRemove(host, port, this);
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
public synchronized void close()
|
||||
{
|
||||
if (persistent)
|
||||
{
|
||||
idle = System.currentTimeMillis();
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheRemove(host, port, this);
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
if (queue.size() > 0) {
|
||||
queue.removeElementAt(0);
|
||||
if (DEBUG) {
|
||||
if (persistent)
|
||||
System.out.println("DONE " + this);
|
||||
else
|
||||
System.out.println("CLOSE " + this);
|
||||
}
|
||||
notify();
|
||||
}
|
||||
if (queue.size() > 0)
|
||||
{
|
||||
queue.removeElementAt(0);
|
||||
if (DEBUG)
|
||||
{
|
||||
if (persistent)
|
||||
System.out.println("DONE " + this);
|
||||
else
|
||||
System.out.println("CLOSE " + this);
|
||||
}
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
private void send(Request request) throws IOException {
|
||||
if (DEBUG) System.out.println("SEND " + request.getURL());
|
||||
private void send(Request request) throws IOException
|
||||
{
|
||||
if (DEBUG) System.out.println("SEND " + request.getURL());
|
||||
|
||||
/* Prepare HTTP/1.1 request */
|
||||
request.removeHeaderField("Proxy-Connection");
|
||||
request.setHeaderField("Connection", "open");
|
||||
if (!request.containsHeaderField("Host")) {
|
||||
request.setHeaderField("Host", request.getHost());
|
||||
}
|
||||
/* Prepare HTTP/1.1 request */
|
||||
request.removeHeaderField("Proxy-Connection");
|
||||
request.setHeaderField("Connection", "open");
|
||||
if (!request.containsHeaderField("Host"))
|
||||
{
|
||||
request.setHeaderField("Host", request.getHost());
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
request.write(getOutputStream());
|
||||
} else {
|
||||
String oldStatusLine = request.statusLine;
|
||||
StringBuffer head = new StringBuffer();
|
||||
head.append(request.getCommand());
|
||||
head.append(" ");
|
||||
head.append(request.getPath());
|
||||
head.append(" ");
|
||||
head.append("HTTP/1.0");
|
||||
request.statusLine = head.toString();
|
||||
if (proxy)
|
||||
{
|
||||
request.write(getOutputStream());
|
||||
}
|
||||
else
|
||||
{
|
||||
String oldStatusLine = request.statusLine;
|
||||
StringBuffer head = new StringBuffer();
|
||||
head.append(request.getCommand());
|
||||
head.append(" ");
|
||||
head.append(request.getPath());
|
||||
head.append(" ");
|
||||
head.append("HTTP/1.0");
|
||||
request.statusLine = head.toString();
|
||||
|
||||
request.write(getOutputStream());
|
||||
request.write(getOutputStream());
|
||||
|
||||
/* flush? */
|
||||
|
||||
request.statusLine = oldStatusLine;
|
||||
}
|
||||
/* flush? */
|
||||
|
||||
request.statusLine = oldStatusLine;
|
||||
}
|
||||
}
|
||||
|
||||
private Reply recv() throws IOException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
reply.read();
|
||||
private Reply recv() throws IOException
|
||||
{
|
||||
Reply reply = new Reply(getInputStream());
|
||||
reply.read();
|
||||
|
||||
String conn = reply.getHeaderField("Connection");
|
||||
String conn = reply.getHeaderField("Connection");
|
||||
|
||||
if (DEBUG) System.out.println("RECV " + reply.statusLine);
|
||||
if (DEBUG) System.out.println("RECV " + reply.statusLine);
|
||||
|
||||
if (reply.containsHeaderField("Connection")
|
||||
&& reply.getHeaderField("Connection").equals("close")) {
|
||||
persistent = false;
|
||||
} else if (reply.getProtocol().equals("HTTP/1.1")) {
|
||||
persistent = true;
|
||||
} else {
|
||||
persistent = false;
|
||||
}
|
||||
if (reply.containsHeaderField("Connection")
|
||||
&& reply.getHeaderField("Connection").equals("close"))
|
||||
{
|
||||
persistent = false;
|
||||
}
|
||||
else if (reply.getProtocol().equals("HTTP/1.1"))
|
||||
{
|
||||
persistent = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
persistent = false;
|
||||
}
|
||||
|
||||
/* Received HTTP/1.1 "Continue". Read another Reply. */
|
||||
if (reply.getStatusCode() == 100) {
|
||||
reply = recv();
|
||||
}
|
||||
/* Received HTTP/1.1 "Continue". Read another Reply. */
|
||||
if (reply.getStatusCode() == 100)
|
||||
{
|
||||
reply = recv();
|
||||
}
|
||||
|
||||
return reply;
|
||||
return reply;
|
||||
}
|
||||
|
||||
private boolean isBusy() {
|
||||
return queue.size() >= MAX_PENDING_REQUESTS;
|
||||
private boolean isBusy()
|
||||
{
|
||||
return queue.size() >= MAX_PENDING_REQUESTS;
|
||||
}
|
||||
|
||||
private boolean isPersistent() {
|
||||
return persistent;
|
||||
private boolean isPersistent()
|
||||
{
|
||||
return persistent;
|
||||
}
|
||||
|
||||
private static String cacheKey(String host, int port) {
|
||||
return host.toLowerCase() + ":" + port;
|
||||
private static String cacheKey(String host, int port)
|
||||
{
|
||||
return host.toLowerCase() + ":" + port;
|
||||
}
|
||||
|
||||
private static Vector cacheLookup(String host, int port) {
|
||||
Vector v = (Vector) cache.get(cacheKey(host, port));
|
||||
return v;
|
||||
private static Vector cacheLookup(String host, int port)
|
||||
{
|
||||
Vector v = (Vector) cache.get(cacheKey(host, port));
|
||||
return v;
|
||||
}
|
||||
|
||||
private static boolean cacheContains(Http http) {
|
||||
Vector v = (Vector) cache.get(cacheKey(http.host, http.port));
|
||||
return v != null ? v.contains(http) : false;
|
||||
private static boolean cacheContains(Http http)
|
||||
{
|
||||
Vector v = (Vector) cache.get(cacheKey(http.host, http.port));
|
||||
return v != null ? v.contains(http) : false;
|
||||
}
|
||||
|
||||
private static void cacheInsert(String host, int port, Http http) {
|
||||
String key = cacheKey(host, port);
|
||||
Vector v = (Vector) cache.get(key);
|
||||
if (v == null) {
|
||||
v = new Vector();
|
||||
}
|
||||
v.addElement(http);
|
||||
cache.put(key, v);
|
||||
private static void cacheInsert(String host, int port, Http http)
|
||||
{
|
||||
String key = cacheKey(host, port);
|
||||
Vector v = (Vector) cache.get(key);
|
||||
if (v == null)
|
||||
{
|
||||
v = new Vector();
|
||||
}
|
||||
v.addElement(http);
|
||||
cache.put(key, v);
|
||||
}
|
||||
|
||||
private static void cacheRemove(String host, int port, Http http) {
|
||||
Vector v = (Vector) cache.get(cacheKey(host, port));
|
||||
if (v != null) {
|
||||
v.removeElement(http);
|
||||
if (v.isEmpty()) {
|
||||
cache.remove(cacheKey(host, port));
|
||||
}
|
||||
}
|
||||
private static void cacheRemove(String host, int port, Http http)
|
||||
{
|
||||
Vector v = (Vector) cache.get(cacheKey(host, port));
|
||||
if (v != null)
|
||||
{
|
||||
v.removeElement(http);
|
||||
if (v.isEmpty())
|
||||
{
|
||||
cache.remove(cacheKey(host, port));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cacheClean() {
|
||||
long now = System.currentTimeMillis();
|
||||
Enumeration e = cache.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Vector v = (Vector) cache.get(e.nextElement());
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
Http http = (Http) v.elementAt(i);
|
||||
if (http.idle > 0 && now - http.idle > 30000) /* 30 seconds */ {
|
||||
if (DEBUG) System.out.println("IDLE " + http);
|
||||
http.persistent = false;
|
||||
http.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void cacheClean()
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
Enumeration e = cache.keys();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
Vector v = (Vector) cache.get(e.nextElement());
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
{
|
||||
Http http = (Http) v.elementAt(i);
|
||||
if (http.idle > 0 && now - http.idle > 30000) /* 30 seconds */
|
||||
{
|
||||
if (DEBUG) System.out.println("IDLE " + http);
|
||||
http.persistent = false;
|
||||
http.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Http open(String host, int port, boolean isProxy)
|
||||
throws IOException {
|
||||
Http http = null;
|
||||
throws IOException
|
||||
{
|
||||
Http http = null;
|
||||
|
||||
synchronized (httpLock) {
|
||||
Vector v = cacheLookup(host, port);
|
||||
if (v != null) {
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
Http pick = (Http) v.elementAt(i);
|
||||
synchronized (httpLock)
|
||||
{
|
||||
Vector v = cacheLookup(host, port);
|
||||
if (v != null)
|
||||
{
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
{
|
||||
Http pick = (Http) v.elementAt(i);
|
||||
|
||||
/* find an http connection that isn't busy */
|
||||
if (pick.isPersistent() && !pick.isBusy()) {
|
||||
http = pick;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* find an http connection that isn't busy */
|
||||
if (pick.isPersistent() && !pick.isBusy())
|
||||
{
|
||||
http = pick;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (http != null) {
|
||||
http.idle = 0;
|
||||
if (DEBUG) System.out.println("REUSE " + http);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (http == null) {
|
||||
if (DEBUG) System.out.println("OPENING " + host + ":" + port);
|
||||
http = new Http(host, port, isProxy);
|
||||
if (DEBUG) System.out.println("OPENED " + http);
|
||||
cacheInsert(host, port, http);
|
||||
}
|
||||
|
||||
return http;
|
||||
if (http != null)
|
||||
{
|
||||
http.idle = 0;
|
||||
if (DEBUG) System.out.println("REUSE " + http);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (http == null)
|
||||
{
|
||||
if (DEBUG) System.out.println("OPENING " + host + ":" + port);
|
||||
http = new Http(host, port, isProxy);
|
||||
if (DEBUG) System.out.println("OPENED " + http);
|
||||
cacheInsert(host, port, http);
|
||||
}
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
static Http open(String host, int port) throws IOException {
|
||||
return open(host, port, false);
|
||||
static Http open(String host, int port) throws IOException
|
||||
{
|
||||
return open(host, port, false);
|
||||
}
|
||||
|
||||
static Enumeration enumerate() {
|
||||
Vector list = new Vector();
|
||||
Enumeration e = cache.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Vector v = (Vector) cache.get(e.nextElement());
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
list.addElement(v.elementAt(i));
|
||||
}
|
||||
}
|
||||
return list.elements();
|
||||
static Enumeration enumerate()
|
||||
{
|
||||
Vector list = new Vector();
|
||||
Enumeration e = cache.keys();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
Vector v = (Vector) cache.get(e.nextElement());
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
{
|
||||
list.addElement(v.elementAt(i));
|
||||
}
|
||||
}
|
||||
return list.elements();
|
||||
}
|
||||
|
||||
static synchronized void clean() {
|
||||
cacheClean();
|
||||
static synchronized void clean()
|
||||
{
|
||||
cacheClean();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("SERVER ");
|
||||
buf.append(super.toString());
|
||||
if (isPersistent()) {
|
||||
buf.append(" - ");
|
||||
if (queue.size() > 0) {
|
||||
buf.append(queue.size());
|
||||
buf.append(" pending");
|
||||
} else {
|
||||
buf.append("idle " + ((System.currentTimeMillis() - idle) / 1000.0) + " sec");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("SERVER ");
|
||||
buf.append(super.toString());
|
||||
if (isPersistent())
|
||||
{
|
||||
buf.append(" - ");
|
||||
if (queue.size() > 0)
|
||||
{
|
||||
buf.append(queue.size());
|
||||
buf.append(" pending");
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.append("idle " + ((System.currentTimeMillis() - idle) / 1000.0) + " sec");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,58 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
abstract class HttpConnection extends Connection implements HttpRelay {
|
||||
HttpConnection(String host, int port) throws IOException {
|
||||
super(host, port);
|
||||
abstract class HttpConnection extends Connection implements HttpRelay
|
||||
{
|
||||
HttpConnection(String host, int port) throws IOException
|
||||
{
|
||||
super(host, port);
|
||||
}
|
||||
|
||||
HttpConnection(Socket s) throws IOException {
|
||||
super(s);
|
||||
HttpConnection(Socket s) throws IOException
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
|
||||
public void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
request.write(getOutputStream());
|
||||
throws IOException, RetryRequestException
|
||||
{
|
||||
request.write(getOutputStream());
|
||||
}
|
||||
|
||||
|
||||
public Reply recvReply(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
reply.read();
|
||||
return reply;
|
||||
throws IOException, RetryRequestException
|
||||
{
|
||||
Reply reply = new Reply(getInputStream());
|
||||
reply.read();
|
||||
return reply;
|
||||
}
|
||||
|
||||
public void setInputStream(InputStream in)
|
||||
{
|
||||
super.setInputStream(in);
|
||||
}
|
||||
|
||||
public void setOutputStream(OutputStream out)
|
||||
{
|
||||
super.setOutputStream(out);
|
||||
}
|
||||
|
||||
public void setInputStream(InputStream in) {
|
||||
super.setInputStream(in);
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream()
|
||||
{
|
||||
return super.getOutputStream();
|
||||
}
|
||||
|
||||
public void setOutputStream(OutputStream out) {
|
||||
super.setOutputStream(out);
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return super.getOutputStream();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
class HttpError
|
||||
{
|
||||
StringBuffer content = null;
|
||||
Reply reply = null;
|
||||
|
||||
HttpError(int code, String message)
|
||||
{
|
||||
String error;
|
||||
switch (code)
|
||||
{
|
||||
case 400:
|
||||
error = "Bad Request";
|
||||
break;
|
||||
|
||||
case 403:
|
||||
error = "Forbidden";
|
||||
break;
|
||||
|
||||
case 404:
|
||||
error = "Not found";
|
||||
break;
|
||||
|
||||
case 503:
|
||||
error = "Service Unavailable";
|
||||
break;
|
||||
|
||||
default:
|
||||
error = "Error";
|
||||
break;
|
||||
}
|
||||
|
||||
reply = new Reply();
|
||||
reply.statusLine = "HTTP/1.0 " + code + " " + error;
|
||||
reply.setHeaderField("Content-type", "text/html");
|
||||
reply.setHeaderField("Server", ProxyConfig.appName+"/" +ProxyConfig.appVersion);
|
||||
|
||||
content = new StringBuffer();
|
||||
content.append(message);
|
||||
}
|
||||
|
||||
Reply getReply()
|
||||
{
|
||||
return reply;
|
||||
}
|
||||
|
||||
String getContent()
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if (reply != null)
|
||||
{
|
||||
buf.append(reply.toString());
|
||||
}
|
||||
if (content != null)
|
||||
{
|
||||
buf.append(content.toString());
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface HttpRelay {
|
||||
public interface HttpRelay
|
||||
{
|
||||
void sendRequest(Request request) throws IOException, RetryRequestException;
|
||||
|
||||
Reply recvReply(Request request) throws IOException, RetryRequestException;
|
||||
|
||||
void close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,39 +2,38 @@ package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
class Https extends HttpConnection {
|
||||
boolean proxy = false;
|
||||
|
||||
Https(String host, int port) throws IOException {
|
||||
super(host, port);
|
||||
}
|
||||
boolean proxy = false;
|
||||
|
||||
Https(String host, int port, boolean isProxy) throws IOException {
|
||||
this(host, port);
|
||||
proxy = isProxy;
|
||||
}
|
||||
Https(String host, int port) throws IOException {
|
||||
super(host, port);
|
||||
}
|
||||
|
||||
public void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
if (proxy) {
|
||||
super.sendRequest(request);
|
||||
} else {
|
||||
/* nothing */
|
||||
}
|
||||
}
|
||||
Https(String host, int port, boolean isProxy) throws IOException {
|
||||
this(host, port);
|
||||
proxy = isProxy;
|
||||
}
|
||||
|
||||
public Reply recvReply(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
if (proxy) {
|
||||
reply.read();
|
||||
} else {
|
||||
reply.statusLine = "HTTP/1.0 200 Connection established";
|
||||
reply.setHeaderField("Proxy-agent", "ASDec");
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
public void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
if (proxy) {
|
||||
super.sendRequest(request);
|
||||
} else {
|
||||
/* nothing */
|
||||
}
|
||||
}
|
||||
|
||||
public Reply recvReply(Request request)
|
||||
throws java.io.IOException, RetryRequestException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
if (proxy) {
|
||||
reply.read();
|
||||
} else {
|
||||
reply.statusLine = "HTTP/1.0 200 Connection established";
|
||||
reply.setHeaderField("Proxy-agent", ProxyConfig.appName);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
class Janitor implements Runnable
|
||||
{
|
||||
private Vector cleanable = new Vector();
|
||||
|
||||
public void add(Cleanable c)
|
||||
{
|
||||
cleanable.addElement(c);
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
Thread.currentThread().setName("Janitor");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(30 * 1000); /* 30 seconds */
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (Enumeration e = cleanable.elements();
|
||||
e.hasMoreElements(); )
|
||||
{
|
||||
((Cleanable)e.nextElement()).clean();
|
||||
}
|
||||
|
||||
Http.clean();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
/**
|
||||
* A wrapper around java.lang.String to have case-insensitive
|
||||
* hashCode and equals methods.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
* @see String
|
||||
*/
|
||||
class Key {
|
||||
private String name = null;
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class LogFile
|
||||
{
|
||||
private static SimpleDateFormat format;
|
||||
private static String zoneString;
|
||||
private String filename = null;
|
||||
private long maxLogFileSize;
|
||||
private int maxLogFileHistory;
|
||||
|
||||
static
|
||||
{
|
||||
format = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
|
||||
format.setTimeZone(TimeZone.getDefault());
|
||||
zoneString = generateZoneString();
|
||||
}
|
||||
|
||||
public LogFile(String filename)
|
||||
{
|
||||
setLogFile(filename);
|
||||
|
||||
maxLogFileSize = ProxyConfig.maxLogFileSize;
|
||||
maxLogFileHistory = ProxyConfig.maxLogFileHistory;
|
||||
}
|
||||
|
||||
public void setLogFile(String filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate the local timezone offset
|
||||
* for PST this is -0800
|
||||
*/
|
||||
private static String generateZoneString()
|
||||
{
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
int offset = calendar.get(Calendar.ZONE_OFFSET)
|
||||
+ calendar.get(Calendar.DST_OFFSET);
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if (offset < 0)
|
||||
{
|
||||
buf.append("-");
|
||||
offset = -offset;
|
||||
}
|
||||
int hours = offset/(60 * 60 * 1000);
|
||||
int mins = (offset%(60 * 60 * 1000)) / (60 * 1000);
|
||||
if (hours < 10)
|
||||
buf.append("0");
|
||||
buf.append(hours);
|
||||
if (mins < 10)
|
||||
buf.append("0");
|
||||
buf.append(mins);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void gzip(File src)
|
||||
{
|
||||
File dst =new File(src.getAbsolutePath() + ".gz");
|
||||
FileInputStream in;
|
||||
GZIPOutputStream out;
|
||||
byte[] buf = new byte[8192];
|
||||
int n;
|
||||
|
||||
try
|
||||
{
|
||||
in = new FileInputStream(src);
|
||||
out = new GZIPOutputStream(new FileOutputStream(dst), buf.length);
|
||||
|
||||
while ((n = in.read(buf)) >= 0)
|
||||
{
|
||||
out.write(buf, 0, n);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rotate(int max)
|
||||
{
|
||||
File f;
|
||||
|
||||
for (int i = max - 2; i >= 1; i--)
|
||||
{
|
||||
f = new File(filename + "." + i + ".gz");
|
||||
if (f.exists())
|
||||
{
|
||||
f.renameTo(new File(filename + "." + (i+1) + ".gz"));
|
||||
}
|
||||
}
|
||||
|
||||
f = new File(filename + ".0");
|
||||
if (f.exists())
|
||||
{
|
||||
gzip(f);
|
||||
f = new File(filename + ".0.gz");
|
||||
f.renameTo(new File(filename + ".1.gz"));
|
||||
}
|
||||
|
||||
f = new File(filename);
|
||||
f.renameTo(new File(filename + ".0"));
|
||||
}
|
||||
|
||||
public synchronized void log(Request request, Reply reply)
|
||||
{
|
||||
int offset;
|
||||
Date date;
|
||||
|
||||
date = new Date();
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(request.getClient().getInetAddress().getHostAddress());
|
||||
buf.append(" - - "); // ident authuser
|
||||
buf.append("[");
|
||||
buf.append(format.format(date));
|
||||
buf.append(" ");
|
||||
buf.append(zoneString);
|
||||
buf.append("] \"");
|
||||
buf.append(request.getRequest());
|
||||
buf.append("\" ");
|
||||
buf.append(reply.getStatusCode());
|
||||
buf.append(" ");
|
||||
int length;
|
||||
try
|
||||
{
|
||||
length = Integer.parseInt(reply.getHeaderField("Content-length"));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
length = 0;
|
||||
}
|
||||
buf.append(length);
|
||||
buf.append("\n");
|
||||
|
||||
if (!ProxyConfig.dontLogFilters)
|
||||
{
|
||||
for (Enumeration h = request.getLogHeaders();
|
||||
h != null && h.hasMoreElements(); )
|
||||
{
|
||||
String header = (String)h.nextElement();
|
||||
buf.append("[");
|
||||
buf.append(header);
|
||||
buf.append("]\n");
|
||||
for (Enumeration e = request.getLogEntries(header);
|
||||
e.hasMoreElements(); )
|
||||
{
|
||||
buf.append("* ");
|
||||
buf.append(e.nextElement().toString());
|
||||
buf.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File file = new File(filename);
|
||||
if (file.length() > maxLogFileSize)
|
||||
{
|
||||
rotate(maxLogFileHistory);
|
||||
}
|
||||
|
||||
FileOutputStream out = new FileOutputStream(filename, true);
|
||||
out.write(buf.toString().getBytes());
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +1,66 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
public static int port = 55555;
|
||||
public static final String REPLACEMENTSFILE = "." + File.separator + "config" + File.separator + "replacements.ini";
|
||||
public static boolean DEBUG_MODE = false;
|
||||
|
||||
|
||||
public static void enterToContinue() {
|
||||
Scanner keyIn = new Scanner(System.in);
|
||||
System.out.print("Press the enter key to continue");
|
||||
keyIn.nextLine();
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].toLowerCase().equals("--help")) {
|
||||
System.out.println("JPEXS Replacement Proxy");
|
||||
System.out.println("-----------------------");
|
||||
System.out.println("Replacements list is read from \"" + REPLACEMENTSFILE + "\" file.");
|
||||
System.out.println("Optional commandline parameters:");
|
||||
System.out.println(" -d");
|
||||
System.out.println(" Print debug info to console ");
|
||||
System.out.println(" -p<NUMBER>");
|
||||
System.out.println(" Set proxy port to <NUMBER>. Default is 55555.");
|
||||
System.exit(0);
|
||||
}
|
||||
if (args[i].toLowerCase().equals("-d")) {
|
||||
System.out.println("DEBUG mode ON");
|
||||
DEBUG_MODE = true;
|
||||
}
|
||||
if (args[i].toLowerCase().startsWith("-p")) {
|
||||
try {
|
||||
port = Integer.parseInt(args[i].substring(2));
|
||||
System.out.println("PORT set to " + port);
|
||||
} catch (NumberFormatException ex) {
|
||||
System.out.println("Invalit port, reset to " + port);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
List<Replacement> replacements = new ArrayList<Replacement>();
|
||||
if ((new File(REPLACEMENTSFILE)).exists()) {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new FileReader(REPLACEMENTSFILE));
|
||||
String s = "";
|
||||
while ((s = br.readLine()) != null) {
|
||||
String fileName = br.readLine();
|
||||
if (fileName == null) break;
|
||||
fileName = fileName.replaceAll("[\\\\/]", File.separator);
|
||||
Replacement r = new Replacement(s, fileName);
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("Added Replacement: " + r.urlPattern + " => " + r.targetFile);
|
||||
}
|
||||
replacements.add(r);
|
||||
}
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("WARNING:REPLACEMENTS FILE NOT FOUND.");
|
||||
}
|
||||
}
|
||||
Server.startServer(port, replacements, new ArrayList<String>(), new CatchedListener() {
|
||||
/**
|
||||
* Method called when specified contentType is received
|
||||
*
|
||||
* @param contentType Content type
|
||||
* @param url URL of the method
|
||||
* @param data Data stream
|
||||
*/
|
||||
public void catched(String contentType, String url, InputStream data) {
|
||||
|
||||
}
|
||||
}, new ReplacedListener() {
|
||||
public void replaced(Replacement replacement, String url, String contentType) {
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("REPLACED:" + url + " (Content-type:" + contentType + ") WITH FILE " + replacement.targetFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Main
|
||||
{
|
||||
|
||||
public static final String REPLACEMENTSFILE = "." + File.separator + "config" + File.separator + "replacements.ini";
|
||||
public static boolean DEBUG_MODE = false;
|
||||
|
||||
public static void main(String argv[])
|
||||
{
|
||||
|
||||
|
||||
List<Replacement> replacements = new ArrayList<Replacement>();
|
||||
if ((new File(REPLACEMENTSFILE)).exists()) {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new FileReader(REPLACEMENTSFILE));
|
||||
String s = "";
|
||||
while ((s = br.readLine()) != null) {
|
||||
String fileName = br.readLine();
|
||||
if (fileName == null) break;
|
||||
fileName = fileName.replaceAll("[\\\\/]", File.separator);
|
||||
Replacement r = new Replacement(s, fileName);
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("Added Replacement: " + r.urlPattern + " => " + r.targetFile);
|
||||
}
|
||||
replacements.add(r);
|
||||
}
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("WARNING:REPLACEMENTS FILE NOT FOUND.");
|
||||
}
|
||||
}
|
||||
Server.startServer(ProxyConfig.port, replacements, new ArrayList<String>(), new CatchedListener() {
|
||||
|
||||
/**
|
||||
* Method called when specified contentType is received
|
||||
*
|
||||
* @param contentType Content type
|
||||
* @param url URL of the method
|
||||
* @param data Data stream
|
||||
*/
|
||||
public void catched(String contentType, String url, InputStream data) {
|
||||
}
|
||||
}, new ReplacedListener() {
|
||||
|
||||
public void replaced(Replacement replacement, String url, String contentType) {
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("REPLACED:" + url + " (Content-type:" + contentType + ") WITH FILE " + replacement.targetFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Abstract class to represent message headers.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public abstract class Message {
|
||||
public abstract class Message
|
||||
{
|
||||
/**
|
||||
* Hashtable used to store message headers.
|
||||
*/
|
||||
@@ -25,158 +17,199 @@ public abstract class Message {
|
||||
*/
|
||||
String statusLine = null;
|
||||
|
||||
public String readLine(InputStream in) throws IOException {
|
||||
char buf[] = new char[128];
|
||||
int offset = 0;
|
||||
int ch;
|
||||
public String readLine(InputStream in) throws IOException
|
||||
{
|
||||
char buf[] = new char[128];
|
||||
int offset = 0;
|
||||
int ch;
|
||||
|
||||
for (; ;) {
|
||||
ch = in.read();
|
||||
if (ch == -1 || ch == '\n') {
|
||||
break;
|
||||
} else if (ch == '\r') {
|
||||
int tmpch = in.read();
|
||||
if (tmpch != '\n') {
|
||||
if (!(in instanceof PushbackInputStream)) {
|
||||
in = new PushbackInputStream(in);
|
||||
}
|
||||
((PushbackInputStream) in).unread(tmpch);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (offset == buf.length) {
|
||||
char tmpbuf[] = buf;
|
||||
buf = new char[tmpbuf.length * 2];
|
||||
System.arraycopy(tmpbuf, 0, buf, 0, offset);
|
||||
}
|
||||
buf[offset++] = (char) ch;
|
||||
}
|
||||
}
|
||||
return String.copyValueOf(buf, 0, offset);
|
||||
for (;;)
|
||||
{
|
||||
ch = in.read();
|
||||
if (ch == -1 || ch == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch == '\r')
|
||||
{
|
||||
int tmpch = in.read();
|
||||
if (tmpch != '\n')
|
||||
{
|
||||
if (! (in instanceof PushbackInputStream))
|
||||
{
|
||||
in = new PushbackInputStream(in);
|
||||
}
|
||||
((PushbackInputStream) in).unread(tmpch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offset == buf.length)
|
||||
{
|
||||
char tmpbuf[] = buf;
|
||||
buf = new char[tmpbuf.length * 2];
|
||||
System.arraycopy(tmpbuf, 0, buf, 0, offset);
|
||||
}
|
||||
buf[offset++] = (char) ch;
|
||||
}
|
||||
}
|
||||
return String.copyValueOf(buf, 0, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read headers and store them in the hashtable.
|
||||
*/
|
||||
void readHeaders(InputStream in) throws IOException {
|
||||
int i;
|
||||
Key key = null;
|
||||
|
||||
for (; ;) {
|
||||
String s = readLine(in);
|
||||
if (s == null) {
|
||||
break;
|
||||
}
|
||||
i = s.indexOf(':');
|
||||
if (i == -1) {
|
||||
/* end of header */
|
||||
if (s.length() == 0) {
|
||||
break;
|
||||
}
|
||||
/* multi-line headers */
|
||||
else if (key != null
|
||||
&& (s.startsWith(" ") || s.startsWith("\t"))) {
|
||||
int index = getHeaderValueCount(key.toString());
|
||||
index--;
|
||||
Vector v = (Vector) headers.get(key);
|
||||
v.setElementAt(v.elementAt(index) + "\n" + s, index);
|
||||
}
|
||||
} else {
|
||||
key = new Key(s.substring(0, i));
|
||||
Vector v;
|
||||
if (headers.containsKey(key)) {
|
||||
v = (Vector) headers.get(key);
|
||||
} else {
|
||||
v = new Vector();
|
||||
}
|
||||
v.addElement(s.substring(i + 1).trim());
|
||||
headers.put(key, v);
|
||||
}
|
||||
}
|
||||
void readHeaders(InputStream in) throws IOException
|
||||
{
|
||||
int i;
|
||||
Key key = null;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
String s = readLine(in);
|
||||
if (s == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i = s.indexOf(':');
|
||||
if (i == -1)
|
||||
{
|
||||
/* end of header */
|
||||
if (s.length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* multi-line headers */
|
||||
else if (key != null
|
||||
&& (s.startsWith(" ") || s.startsWith("\t")))
|
||||
{
|
||||
int index = getHeaderValueCount(key.toString());
|
||||
index--;
|
||||
Vector v = (Vector) headers.get(key);
|
||||
v.setElementAt(v.elementAt(index) + "\n" + s, index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key = new Key(s.substring(0, i));
|
||||
Vector v;
|
||||
if (headers.containsKey(key))
|
||||
{
|
||||
v = (Vector) headers.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = new Vector();
|
||||
}
|
||||
v.addElement(s.substring(i+1).trim());
|
||||
headers.put(key, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int headerCount() {
|
||||
return headers.size();
|
||||
public int headerCount()
|
||||
{
|
||||
return headers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Status line.
|
||||
*/
|
||||
public void setStatusLine(String l) {
|
||||
public void setStatusLine(String l)
|
||||
{
|
||||
statusLine = l;
|
||||
}
|
||||
|
||||
public int getHeaderValueCount(String name) {
|
||||
Vector v = (Vector) headers.get(new Key(name));
|
||||
return v.size();
|
||||
public int getHeaderValueCount(String name)
|
||||
{
|
||||
Vector v = (Vector) headers.get(new Key(name));
|
||||
return v.size();
|
||||
}
|
||||
|
||||
public String getHeaderField(String name)
|
||||
{
|
||||
return getHeaderField(name, 0);
|
||||
}
|
||||
|
||||
public String getHeaderField(String name, int index)
|
||||
{
|
||||
Vector v = (Vector) headers.get(new Key(name));
|
||||
if (v == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (String) v.elementAt(index);
|
||||
}
|
||||
|
||||
public String getHeaderField(String name) {
|
||||
return getHeaderField(name, 0);
|
||||
public void setHeaderField(String name, String value)
|
||||
{
|
||||
setHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public String getHeaderField(String name, int index) {
|
||||
Vector v = (Vector) headers.get(new Key(name));
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
return (String) v.elementAt(index);
|
||||
public void setHeaderField(String name, String value, int index)
|
||||
{
|
||||
Vector v;
|
||||
Key key = new Key(name);
|
||||
|
||||
if (headers.containsKey(key))
|
||||
{
|
||||
v = (Vector) headers.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = new Vector();
|
||||
if (index == 0)
|
||||
{
|
||||
v.addElement("");
|
||||
}
|
||||
headers.put(key, v);
|
||||
}
|
||||
v.setElementAt(value, index);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, int value)
|
||||
{
|
||||
setHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, String value) {
|
||||
setHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, String value, int index) {
|
||||
Vector v;
|
||||
Key key = new Key(name);
|
||||
|
||||
if (headers.containsKey(key)) {
|
||||
v = (Vector) headers.get(key);
|
||||
} else {
|
||||
v = new Vector();
|
||||
if (index == 0) {
|
||||
v.addElement("");
|
||||
}
|
||||
headers.put(key, v);
|
||||
}
|
||||
v.setElementAt(value, index);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, int value) {
|
||||
setHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, int value, int index) {
|
||||
setHeaderField(name, new Integer(value).toString(), index);
|
||||
public void setHeaderField(String name, int value, int index)
|
||||
{
|
||||
setHeaderField(name, new Integer(value).toString(), index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all header fields with the give name to the
|
||||
* specified value.
|
||||
*/
|
||||
public void setHeaderFields(String name, String value) {
|
||||
Vector v;
|
||||
Key key = new Key(name);
|
||||
public void setHeaderFields(String name, String value)
|
||||
{
|
||||
Vector v;
|
||||
Key key = new Key(name);
|
||||
|
||||
v = (Vector) headers.get(key);
|
||||
if (v != null) {
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
v.setElementAt(value, i);
|
||||
}
|
||||
}
|
||||
v = (Vector) headers.get(key);
|
||||
if (v != null)
|
||||
{
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
{
|
||||
v.setElementAt(value, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendHeaderField(String name, String value) {
|
||||
appendHeaderField(name, value, 0);
|
||||
public void appendHeaderField(String name, String value)
|
||||
{
|
||||
appendHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void appendHeaderField(String name, String value, int index) {
|
||||
setHeaderField(name, getHeaderField(name, index) + value, index);
|
||||
|
||||
public void appendHeaderField(String name, String value, int index)
|
||||
{
|
||||
setHeaderField(name, getHeaderField(name, index) + value, index);
|
||||
}
|
||||
|
||||
public void removeHeaderField(String name) {
|
||||
headers.remove(new Key(name));
|
||||
|
||||
public void removeHeaderField(String name)
|
||||
{
|
||||
headers.remove(new Key(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,70 +217,81 @@ public abstract class Message {
|
||||
*
|
||||
* @param name header name
|
||||
*/
|
||||
public boolean containsHeaderField(String name) {
|
||||
return headers.containsKey(new Key(name));
|
||||
public boolean containsHeaderField(String name)
|
||||
{
|
||||
return headers.containsKey(new Key(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an Enumeration of Strings
|
||||
*/
|
||||
public Enumeration getHeaders() {
|
||||
Vector v = new Vector();
|
||||
public Enumeration getHeaders()
|
||||
{
|
||||
Vector v = new Vector();
|
||||
|
||||
for (Enumeration e = headers.keys(); e.hasMoreElements();) {
|
||||
v.addElement(e.nextElement().toString());
|
||||
}
|
||||
for (Enumeration e = headers.keys(); e.hasMoreElements(); )
|
||||
{
|
||||
v.addElement(e.nextElement().toString());
|
||||
}
|
||||
|
||||
return v.elements();
|
||||
return v.elements();
|
||||
}
|
||||
|
||||
private final static byte[] COLON_SPACE = ": ".getBytes();
|
||||
private final static byte[] CRLF = "\r\n".getBytes();
|
||||
|
||||
private ByteArray toByteArray(byte[] sep)
|
||||
{
|
||||
ByteArray buf = new ByteArray();
|
||||
Key key;
|
||||
String value;
|
||||
Vector v;
|
||||
int i = 0;
|
||||
|
||||
buf.append(statusLine);
|
||||
buf.append(sep);
|
||||
|
||||
for (Enumeration e = headers.keys(); e.hasMoreElements(); )
|
||||
{
|
||||
key = (Key) e.nextElement();
|
||||
v = (Vector) headers.get(key);
|
||||
for (i = 0; i < v.size(); i++)
|
||||
{
|
||||
buf.append(key.toString());
|
||||
buf.append(COLON_SPACE);
|
||||
buf.append(v.elementAt(i).toString());
|
||||
buf.append(sep);
|
||||
}
|
||||
}
|
||||
buf.append(sep);
|
||||
|
||||
private ByteArray toByteArray(byte[] sep) {
|
||||
ByteArray buf = new ByteArray();
|
||||
Key key;
|
||||
String value;
|
||||
Vector v;
|
||||
int i = 0;
|
||||
|
||||
buf.append(statusLine);
|
||||
buf.append(sep);
|
||||
|
||||
for (Enumeration e = headers.keys(); e.hasMoreElements();) {
|
||||
key = (Key) e.nextElement();
|
||||
v = (Vector) headers.get(key);
|
||||
for (i = 0; i < v.size(); i++) {
|
||||
buf.append(key.toString());
|
||||
buf.append(COLON_SPACE);
|
||||
buf.append(v.elementAt(i).toString());
|
||||
buf.append(sep);
|
||||
}
|
||||
}
|
||||
buf.append(sep);
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
private ByteArray toByteArray() {
|
||||
return toByteArray(CRLF);
|
||||
private ByteArray toByteArray()
|
||||
{
|
||||
return toByteArray(CRLF);
|
||||
}
|
||||
|
||||
private ByteArray toByteArray(String sep) {
|
||||
return toByteArray(sep.getBytes());
|
||||
private ByteArray toByteArray(String sep)
|
||||
{
|
||||
return toByteArray(sep.getBytes());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toByteArray().toString();
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return toByteArray().toString();
|
||||
}
|
||||
|
||||
public String toString(String sep) {
|
||||
return toByteArray(sep).toString();
|
||||
|
||||
public String toString(String sep)
|
||||
{
|
||||
return toByteArray(sep).toString();
|
||||
}
|
||||
|
||||
public void write(OutputStream out)
|
||||
throws IOException {
|
||||
toByteArray().writeTo(out);
|
||||
out.flush();
|
||||
throws IOException
|
||||
{
|
||||
toByteArray().writeTo(out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ProxyConfig {
|
||||
|
||||
public static boolean dontLogFilters=false;
|
||||
public static long maxLogFileSize=1024*5;
|
||||
public static int maxLogFileHistory=500;
|
||||
|
||||
public static String appVersion="1.1";
|
||||
public static String appName="JPProxy";
|
||||
public static int port=55555;
|
||||
public static String bindAddress;
|
||||
|
||||
public static int readTimeout=50000;
|
||||
public static boolean proxyKeepAlive=false;
|
||||
public static boolean dontUncompress=false;
|
||||
|
||||
public static boolean useHTTPSProxy=false;
|
||||
public static String httpsProxyHost="";
|
||||
public static int httpsProxyPort=0;
|
||||
|
||||
public static boolean useHTTPProxy=false;
|
||||
public static String httpProxyHost="";
|
||||
public static int httpProxyPort=0;
|
||||
|
||||
}
|
||||
@@ -1,203 +1,245 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringBufferInputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class Reply extends Message {
|
||||
public class Reply extends Message
|
||||
{
|
||||
InputStream in = null;
|
||||
int statusCode = -1;
|
||||
|
||||
public Reply() {
|
||||
public Reply()
|
||||
{
|
||||
}
|
||||
|
||||
public Reply(InputStream in) {
|
||||
setContent(in);
|
||||
public Reply(InputStream in)
|
||||
{
|
||||
setContent(in);
|
||||
}
|
||||
|
||||
public void setContent(InputStream in) {
|
||||
this.in = in;
|
||||
public void setContent(InputStream in)
|
||||
{
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public InputStream getContent() {
|
||||
return in;
|
||||
public InputStream getContent()
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
void read() throws IOException
|
||||
{
|
||||
if (in != null)
|
||||
{
|
||||
read(in);
|
||||
}
|
||||
}
|
||||
|
||||
void read(InputStream in) throws IOException
|
||||
{
|
||||
statusLine = readLine(in);
|
||||
if (statusLine == null || statusLine.length() == 0)
|
||||
{
|
||||
throw new IOException("Missing HTTP status line");
|
||||
}
|
||||
|
||||
/* Look for HTTP/0.9 */
|
||||
if (!statusLine.startsWith("HTTP"))
|
||||
{
|
||||
/* Put back the line */
|
||||
if (this.in != null)
|
||||
{
|
||||
String putback = new String(statusLine + "\n");
|
||||
this.in = new SequenceInputStream(new StringBufferInputStream(putback), in);
|
||||
}
|
||||
/* Fake a status line and upgrade to HTTP/1.0 */
|
||||
statusLine = "HTTP/1.0 200 OK";
|
||||
return;
|
||||
}
|
||||
|
||||
readHeaders(in);
|
||||
int code = getStatusCode();
|
||||
|
||||
/* RFC 2068: 204 and 304 MUST NOT contain a message body. */
|
||||
switch (code)
|
||||
{
|
||||
case 204: /* No Content */
|
||||
case 304: /* Not Modified */
|
||||
/* Ignore the message body if it exists */
|
||||
if (containsHeaderField("Content-length"))
|
||||
{
|
||||
int contentLength = 0;
|
||||
try
|
||||
{
|
||||
contentLength = Integer.parseInt(getHeaderField("Content-length"));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
}
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
while ((n = in.read(buffer, 0, buffer.length)) > 0)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
removeHeaderField("Content-length");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void read() throws IOException {
|
||||
if (in != null) {
|
||||
read(in);
|
||||
}
|
||||
public boolean hasContent()
|
||||
{
|
||||
switch (getStatusCode())
|
||||
{
|
||||
case 204:
|
||||
case 304:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void read(InputStream in) throws IOException {
|
||||
statusLine = readLine(in);
|
||||
if (statusLine == null || statusLine.length() == 0) {
|
||||
throw new IOException("Missing HTTP status line");
|
||||
}
|
||||
|
||||
/* Look for HTTP/0.9 */
|
||||
if (!statusLine.startsWith("HTTP")) {
|
||||
/* Put back the line */
|
||||
if (this.in != null) {
|
||||
String putback = new String(statusLine + "\n");
|
||||
this.in = new SequenceInputStream(new ByteArrayInputStream(putback.getBytes("utf8")), in);
|
||||
}
|
||||
/* Fake a status line and upgrade to HTTP/1.0 */
|
||||
statusLine = "HTTP/1.0 200 OK";
|
||||
return;
|
||||
}
|
||||
|
||||
readHeaders(in);
|
||||
int code = getStatusCode();
|
||||
|
||||
/* RFC 2068: 204 and 304 MUST NOT contain a message body. */
|
||||
switch (code) {
|
||||
case 204: /* No Content */
|
||||
case 304: /* Not Modified */
|
||||
/* Ignore the message body if it exists */
|
||||
if (containsHeaderField("Content-length")) {
|
||||
int contentLength = 0;
|
||||
try {
|
||||
contentLength = Integer.parseInt(getHeaderField("Content-length"));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
}
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
while ((n = in.read(buffer, 0, buffer.length)) > 0) {
|
||||
/* ignore */
|
||||
}
|
||||
removeHeaderField("Content-length");
|
||||
}
|
||||
break;
|
||||
}
|
||||
public String getProtocol()
|
||||
{
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
String protocol = (String) st.nextToken();
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public boolean hasContent() {
|
||||
switch (getStatusCode()) {
|
||||
case 204:
|
||||
case 304:
|
||||
return false;
|
||||
public int getStatusCode()
|
||||
{
|
||||
if (statusCode == -1)
|
||||
{
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
String protocol = (String) st.nextToken();
|
||||
String status = (String) st.nextToken();
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
try
|
||||
{
|
||||
statusCode = Integer.parseInt(status);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
System.out.println("Malformed or missing status code");
|
||||
statusCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
String protocol = (String) st.nextToken();
|
||||
return protocol;
|
||||
private Hashtable headerParser(String header)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
String type = getHeaderField(header);
|
||||
if (type == null)
|
||||
{
|
||||
return table;
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer(type, ";");
|
||||
int count = 0;
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
String token = st.nextToken();
|
||||
token = token.trim();
|
||||
String name;
|
||||
String value;
|
||||
int i = token.indexOf('=');
|
||||
if (i != -1)
|
||||
{
|
||||
name = token.substring(0, i);
|
||||
value = token.substring(i+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = token;
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
table.put(header, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
table.put(name, value);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
if (statusCode == -1) {
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
String protocol = (String) st.nextToken();
|
||||
String status = (String) st.nextToken();
|
||||
|
||||
try {
|
||||
statusCode = Integer.parseInt(status);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
statusCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return statusCode;
|
||||
public String getContentType()
|
||||
{
|
||||
Hashtable table = headerParser("Content-type");
|
||||
return(String) table.get("Content-type");
|
||||
}
|
||||
|
||||
private Hashtable headerParser(String header) {
|
||||
Hashtable table = new Hashtable();
|
||||
String type = getHeaderField(header);
|
||||
if (type == null) {
|
||||
return table;
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer(type, ";");
|
||||
int count = 0;
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken();
|
||||
token = token.trim();
|
||||
String name;
|
||||
String value;
|
||||
int i = token.indexOf('=');
|
||||
if (i != -1) {
|
||||
name = token.substring(0, i);
|
||||
value = token.substring(i + 1);
|
||||
} else {
|
||||
name = token;
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
table.put(header, name);
|
||||
} else {
|
||||
table.put(name, value);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return table;
|
||||
public String getBoundary()
|
||||
{
|
||||
Hashtable table = headerParser("Content-type");
|
||||
return(String) table.get("boundary");
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
Hashtable table = headerParser("Content-type");
|
||||
return (String) table.get("Content-type");
|
||||
public String getTransferEncoding()
|
||||
{
|
||||
Hashtable table = headerParser("Transfer-Encoding");
|
||||
return(String) table.get("Transfer-Encoding");
|
||||
}
|
||||
|
||||
public String getBoundary() {
|
||||
Hashtable table = headerParser("Content-type");
|
||||
return (String) table.get("boundary");
|
||||
public int getChunkSize(InputStream in) throws IOException
|
||||
{
|
||||
String line = readLine(in);
|
||||
line = line.trim(); /* apache can have trailing spaces */
|
||||
int size = -1;
|
||||
try
|
||||
{
|
||||
size = Integer.valueOf(line, 16).intValue();
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
System.out.println(e);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getTransferEncoding() {
|
||||
Hashtable table = headerParser("Transfer-Encoding");
|
||||
return (String) table.get("Transfer-Encoding");
|
||||
public void getChunkedFooter(InputStream in) throws IOException
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
String line = readLine(in);
|
||||
if (line == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
int i = line.indexOf(':');
|
||||
if (i == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getChunkSize(InputStream in) throws IOException {
|
||||
String line = readLine(in);
|
||||
line = line.trim(); /* apache can have trailing spaces */
|
||||
int size = -1;
|
||||
try {
|
||||
size = Integer.valueOf(line, 16).intValue();
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
return size;
|
||||
public void setStatusLine(String line)
|
||||
{
|
||||
this.statusLine = line;
|
||||
}
|
||||
|
||||
public void getChunkedFooter(InputStream in) throws IOException {
|
||||
for (; ;) {
|
||||
String line = readLine(in);
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
int i = line.indexOf(':');
|
||||
if (i == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
public static Reply createRedirect(String url)
|
||||
{
|
||||
Reply r = new Reply();
|
||||
r.setStatusLine("HTTP/1.0 302 Moved Temporarily");
|
||||
r.setHeaderField("Location", url);
|
||||
return r;
|
||||
}
|
||||
|
||||
public void setStatusLine(String line) {
|
||||
this.statusLine = line;
|
||||
}
|
||||
|
||||
public static Reply createRedirect(String url) {
|
||||
Reply r = new Reply();
|
||||
r.setStatusLine("HTTP/1.0 302 Moved Temporarily");
|
||||
r.setHeaderField("Location", url);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,235 +1,265 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class Request extends Message {
|
||||
private static Pattern httpRegex;
|
||||
public class Request extends Message
|
||||
{
|
||||
|
||||
private String command = null;
|
||||
private String url = null;
|
||||
private String protocol = null;
|
||||
private byte[] data = null;
|
||||
private Client client = null;
|
||||
private Hashtable log;
|
||||
private Vector logHeaders;
|
||||
private Client client;
|
||||
|
||||
static {
|
||||
httpRegex = Pattern.compile("^(http|https):", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
Request(Client c)
|
||||
{
|
||||
client = c;
|
||||
}
|
||||
|
||||
public Request(Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
void read(InputStream in) throws IOException
|
||||
{
|
||||
statusLine = readLine(in);
|
||||
if (statusLine == null || statusLine.length() == 0)
|
||||
{
|
||||
throw new IOException("Empty request");
|
||||
}
|
||||
|
||||
void read(InputStream in) throws IOException {
|
||||
statusLine = readLine(in);
|
||||
if (statusLine == null || statusLine.length() == 0) {
|
||||
throw new IOException("Empty request");
|
||||
}
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
command = (String) st.nextToken();
|
||||
url = (String) st.nextToken();
|
||||
protocol = (String) st.nextToken();
|
||||
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
command = (String) st.nextToken();
|
||||
url = (String) st.nextToken();
|
||||
protocol = (String) st.nextToken();
|
||||
if (!url.startsWith("http"))
|
||||
{
|
||||
//TODO do something here
|
||||
}
|
||||
|
||||
if (!url.startsWith("http")) {
|
||||
Matcher match = httpRegex.matcher(url);
|
||||
if (match.matches()) {
|
||||
url = url.substring(match.start(),
|
||||
match.end()).toLowerCase()
|
||||
+ url.substring(match.end());
|
||||
}
|
||||
}
|
||||
readHeaders(in);
|
||||
|
||||
readHeaders(in);
|
||||
|
||||
if ("POST".equals(command) || "PUT".equals(command)) {
|
||||
try {
|
||||
int n = Integer.parseInt(getHeaderField("Content-length"));
|
||||
data = new byte[n];
|
||||
int offset = 0;
|
||||
while (offset < data.length) {
|
||||
n = in.read(data, offset, data.length - offset);
|
||||
if (n < 0) {
|
||||
throw new IOException("Not enough " + command + " data");
|
||||
}
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println("Malformed or missing " + command + " Content-length");
|
||||
}
|
||||
}
|
||||
if ("POST".equals(command) || "PUT".equals(command))
|
||||
{
|
||||
try
|
||||
{
|
||||
int n = Integer.parseInt(getHeaderField("Content-length"));
|
||||
data = new byte[n];
|
||||
int offset = 0;
|
||||
while (offset < data.length)
|
||||
{
|
||||
n = in.read(data, offset, data.length - offset);
|
||||
if (n < 0)
|
||||
{
|
||||
throw new IOException("Not enough " + command + " data");
|
||||
}
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
System.out.println("Malformed or missing " + command + " Content-length");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(OutputStream out)
|
||||
throws IOException {
|
||||
super.write(out);
|
||||
if (data != null) {
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
throws IOException
|
||||
{
|
||||
super.write(out);
|
||||
if (data != null)
|
||||
{
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public String getRequest() {
|
||||
return statusLine;
|
||||
public String getRequest()
|
||||
{
|
||||
return statusLine;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
public String getCommand()
|
||||
{
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(String command)
|
||||
{
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
public String getURL()
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return url;
|
||||
public void setURL(String url)
|
||||
{
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setURL(String url) {
|
||||
this.url = url;
|
||||
public String getProtocol()
|
||||
{
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
public void setProtocol(String protocol)
|
||||
{
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
public String getHost()
|
||||
{
|
||||
String url = getURL();
|
||||
String s;
|
||||
|
||||
if (url.startsWith("http://"))
|
||||
{
|
||||
s = url.substring(7, url.indexOf('/', 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
s = url;
|
||||
}
|
||||
|
||||
int at = s.indexOf('@');
|
||||
if (at != -1 )
|
||||
{
|
||||
s = s.substring(at+1);
|
||||
}
|
||||
|
||||
if (s.indexOf(':') != -1)
|
||||
{
|
||||
return s.substring(0, s.indexOf(':'));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
String url = getURL();
|
||||
String s;
|
||||
public int getPort()
|
||||
{
|
||||
int port = 80;
|
||||
String url = getURL();
|
||||
String s;
|
||||
|
||||
if (url.startsWith("http://")) {
|
||||
s = url.substring(7, url.indexOf('/', 7));
|
||||
} else {
|
||||
s = url;
|
||||
}
|
||||
if (url.startsWith("http://"))
|
||||
{
|
||||
s = url.substring(7, url.indexOf('/', 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
s = url;
|
||||
}
|
||||
|
||||
int at = s.indexOf('@');
|
||||
if (at != -1) {
|
||||
s = s.substring(at + 1);
|
||||
}
|
||||
int at = s.indexOf('@');
|
||||
if (at != -1 )
|
||||
{
|
||||
s = s.substring(at+1);
|
||||
}
|
||||
|
||||
if (s.indexOf(':') != -1) {
|
||||
return s.substring(0, s.indexOf(':'));
|
||||
}
|
||||
|
||||
return s;
|
||||
if (s.indexOf(':') != -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
port = Integer.parseInt(s.substring(s.indexOf(':') + 1));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
System.out.println("Invalid port in " + url);
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
int port = 80;
|
||||
String url = getURL();
|
||||
String s;
|
||||
|
||||
if (url.startsWith("http://")) {
|
||||
s = url.substring(7, url.indexOf('/', 7));
|
||||
} else {
|
||||
s = url;
|
||||
}
|
||||
|
||||
int at = s.indexOf('@');
|
||||
if (at != -1) {
|
||||
s = s.substring(at + 1);
|
||||
}
|
||||
|
||||
if (s.indexOf(':') != -1) {
|
||||
try {
|
||||
port = Integer.parseInt(s.substring(s.indexOf(':') + 1));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println("Invalid port in " + url);
|
||||
}
|
||||
}
|
||||
return port;
|
||||
public String getData()
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new String(data);
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return new String(data);
|
||||
public String getPath()
|
||||
{
|
||||
String str = getURL();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
pos = str.indexOf('/', pos);
|
||||
pos++;
|
||||
}
|
||||
pos--;
|
||||
return str.substring(pos);
|
||||
}
|
||||
|
||||
public String getDocument()
|
||||
{
|
||||
String path = getPath();
|
||||
int n = path.lastIndexOf('/');
|
||||
if (n == path.length() - 1)
|
||||
{
|
||||
n = path.lastIndexOf('/', n - 1);
|
||||
}
|
||||
if (n < 0)
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
return path.substring(n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getDataBytes() {
|
||||
return data;
|
||||
public Client getClient()
|
||||
{
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
public String getPath() {
|
||||
String str = getURL();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
pos = str.indexOf('/', pos);
|
||||
pos++;
|
||||
}
|
||||
pos--;
|
||||
return str.substring(pos);
|
||||
}
|
||||
|
||||
public String getDocument() {
|
||||
String path = getPath();
|
||||
int n = path.lastIndexOf('/');
|
||||
if (n == path.length() - 1) {
|
||||
n = path.lastIndexOf('/', n - 1);
|
||||
}
|
||||
if (n < 0) {
|
||||
return "/";
|
||||
} else {
|
||||
return path.substring(n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getQueryString() {
|
||||
String path = getPath();
|
||||
int n = path.indexOf('?');
|
||||
if (n < 0) {
|
||||
return null;
|
||||
}
|
||||
return path.substring(n + 1);
|
||||
public String getQueryString()
|
||||
{
|
||||
String path = getPath();
|
||||
int n = path.indexOf('?');
|
||||
if (n < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return path.substring(n + 1);
|
||||
}
|
||||
|
||||
public synchronized void addLogEntry(String header,
|
||||
String message) {
|
||||
if (log == null) {
|
||||
log = new Hashtable();
|
||||
logHeaders = new Vector();
|
||||
}
|
||||
String message)
|
||||
{
|
||||
if (log == null)
|
||||
{
|
||||
log = new Hashtable();
|
||||
logHeaders = new Vector();
|
||||
}
|
||||
|
||||
Vector v = (Vector) log.get(header);
|
||||
if (log.get(header) == null) {
|
||||
v = new Vector();
|
||||
log.put(header, v);
|
||||
logHeaders.addElement(header);
|
||||
}
|
||||
v.addElement(message);
|
||||
Vector v = (Vector)log.get(header);
|
||||
if (log.get(header) == null)
|
||||
{
|
||||
v = new Vector();
|
||||
log.put(header, v);
|
||||
logHeaders.addElement(header);
|
||||
}
|
||||
v.addElement(message);
|
||||
}
|
||||
|
||||
public Enumeration getLogHeaders() {
|
||||
return logHeaders != null ? logHeaders.elements() : null;
|
||||
public Enumeration getLogHeaders()
|
||||
{
|
||||
return logHeaders != null ? logHeaders.elements() : null;
|
||||
}
|
||||
|
||||
public Enumeration getLogEntries(String header) {
|
||||
return log != null ? ((Vector) log.get(header)).elements() : null;
|
||||
public Enumeration getLogEntries(String header)
|
||||
{
|
||||
return log != null ? ((Vector)log.get(header)).elements() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
class RetryRequestException extends Exception {
|
||||
RetryRequestException() {
|
||||
super();
|
||||
class RetryRequestException extends Exception
|
||||
{
|
||||
RetryRequestException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
RetryRequestException(String message) {
|
||||
super(message);
|
||||
|
||||
RetryRequestException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
public class ReusableThread extends Thread
|
||||
{
|
||||
private ThreadPool pool = null;
|
||||
private Runnable runnable = null;
|
||||
private boolean alive = true;
|
||||
private long lastrun = 0;
|
||||
private int used = 0;
|
||||
|
||||
public ReusableThread(ThreadPool pool)
|
||||
{
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public synchronized void setRunnable(Runnable runnable)
|
||||
{
|
||||
this.runnable = runnable;
|
||||
notify();
|
||||
}
|
||||
|
||||
public synchronized void terminate()
|
||||
{
|
||||
alive = false;
|
||||
notify();
|
||||
}
|
||||
|
||||
public long getLastRunTime()
|
||||
{
|
||||
return lastrun;
|
||||
}
|
||||
|
||||
public int useCount()
|
||||
{
|
||||
return used;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (alive)
|
||||
{
|
||||
setName("ReusableThread: idle");
|
||||
|
||||
while (runnable == null && alive)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
try
|
||||
{
|
||||
wait();
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alive)
|
||||
{
|
||||
setName("ReusableThread: busy");
|
||||
setPriority(Thread.NORM_PRIORITY);
|
||||
lastrun = System.currentTimeMillis();
|
||||
used++;
|
||||
runnable.run();
|
||||
runnable = null;
|
||||
pool.put(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +1,161 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Proxy server
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Server extends Thread {
|
||||
private ServerSocket ssocket = null;
|
||||
private boolean stoppped = false;
|
||||
private List<Replacement> replacements;
|
||||
private static Server server;
|
||||
private List<String> catchedContentTypes;
|
||||
private CatchedListener catchedListener;
|
||||
private int port;
|
||||
private ReplacedListener replacedListener;
|
||||
|
||||
private Server(int port, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
|
||||
this.replacements = replacements;
|
||||
this.catchedContentTypes = catchedContentTypes;
|
||||
this.catchedListener = catchedListener;
|
||||
this.replacedListener = replacedListener;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
private void stopRun() {
|
||||
stoppped = true;
|
||||
if (ssocket != null) {
|
||||
try {
|
||||
ssocket.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts proxy server
|
||||
*
|
||||
* @param port Listening port
|
||||
* @param replacements List of replacements
|
||||
* @param catchedContentTypes Content types to sniff
|
||||
* @param catchedListener Catched listener
|
||||
*/
|
||||
public static void startServer(int port, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
|
||||
stopServer();
|
||||
server = new Server(port, replacements, catchedContentTypes, catchedListener, replacedListener);
|
||||
//WorkerThread.assignThread(server, "Proxy server");
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops proxy server
|
||||
*/
|
||||
public static void stopServer() {
|
||||
if (server != null) server.stopRun();
|
||||
server = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the server
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
ssocket = new ServerSocket(port);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Cannot bind to port");
|
||||
return;
|
||||
}
|
||||
for (; ;) {
|
||||
try {
|
||||
Socket sock = ssocket.accept();
|
||||
Handler handler = new Handler(sock, replacements, catchedContentTypes, catchedListener, replacedListener);
|
||||
WorkerThread.assignThread(handler, "Proxy handler");
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
if (stoppped)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.ServerSocket;
|
||||
import java.io.IOException;
|
||||
import java.io.DataOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class Server implements Runnable
|
||||
{
|
||||
ServerSocket server = null;
|
||||
boolean running = false;
|
||||
|
||||
private List<String> catchedContentTypes;
|
||||
private CatchedListener catchedListener;
|
||||
private ReplacedListener replacedListener;
|
||||
private List<Replacement> replacements;
|
||||
|
||||
static ThreadPool pool;
|
||||
|
||||
static Server myServer;
|
||||
static boolean serverRunning=false;
|
||||
|
||||
static boolean stopping=false;
|
||||
|
||||
public static ReusableThread getThread()
|
||||
{
|
||||
return pool.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts proxy server
|
||||
*
|
||||
* @param port Listening port
|
||||
* @param replacements List of replacements
|
||||
* @param catchedContentTypes Content types to sniff
|
||||
* @param catchedListener Catched listener
|
||||
*/
|
||||
public static boolean startServer(int port, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
|
||||
stopServer();
|
||||
try {
|
||||
myServer = new Server(port, replacements, catchedContentTypes, catchedListener, replacedListener);
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
pool = new ThreadPool(ProxyConfig.appName+" Threads");
|
||||
/* Startup the Janitor */
|
||||
Janitor j = new Janitor();
|
||||
j.add(pool);
|
||||
getThread().setRunnable(j);
|
||||
serverRunning=true;
|
||||
getThread().setRunnable(myServer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static void stopServer()
|
||||
{
|
||||
if(serverRunning){
|
||||
serverRunning=false;
|
||||
try {
|
||||
myServer.server.close();
|
||||
} catch (IOException ex) {
|
||||
|
||||
}
|
||||
pool.clean();
|
||||
}
|
||||
}
|
||||
Server(int port,List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) throws IOException
|
||||
{
|
||||
|
||||
this.replacements = replacements;
|
||||
this.catchedContentTypes = catchedContentTypes;
|
||||
this.catchedListener = catchedListener;
|
||||
this.replacedListener = replacedListener;
|
||||
|
||||
try
|
||||
{
|
||||
String bindaddr = ProxyConfig.bindAddress;
|
||||
if (bindaddr != null && bindaddr.length() > 0)
|
||||
{
|
||||
server = new ServerSocket(port, 512,
|
||||
InetAddress.getByName(bindaddr));
|
||||
}
|
||||
else
|
||||
{
|
||||
server = new ServerSocket(port, 512);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
/* Initialize internal Httpd */
|
||||
}
|
||||
|
||||
synchronized void suspend()
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
|
||||
synchronized void resume()
|
||||
{
|
||||
running = true;
|
||||
}
|
||||
|
||||
|
||||
public void run()
|
||||
{
|
||||
Thread.currentThread().setName(ProxyConfig.appName+" Server");
|
||||
running = true;
|
||||
for (;;)
|
||||
{
|
||||
Socket socket;
|
||||
|
||||
try
|
||||
{
|
||||
socket = server.accept();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if(stopping){
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(stopping){
|
||||
break;
|
||||
}
|
||||
|
||||
if (running)
|
||||
{
|
||||
Handler h = new Handler(socket,replacements,catchedContentTypes,catchedListener,replacedListener);
|
||||
ReusableThread rt = getThread();
|
||||
rt.setRunnable(h);
|
||||
}
|
||||
else
|
||||
{
|
||||
error(socket, 503, ProxyConfig.appName+" proxy service is suspended.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void error(Socket socket, int code, String message)
|
||||
{
|
||||
try
|
||||
{
|
||||
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
|
||||
out.writeBytes((new HttpError(code, message)).toString());
|
||||
out.close();
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ThreadPool implements Cleanable
|
||||
{
|
||||
private String name;
|
||||
private Vector pool = new Vector();
|
||||
|
||||
public ThreadPool(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public synchronized ReusableThread get()
|
||||
{
|
||||
ReusableThread rt = null;
|
||||
|
||||
if (pool.size() > 0)
|
||||
{
|
||||
rt = (ReusableThread)pool.firstElement();
|
||||
pool.removeElement(rt);
|
||||
}
|
||||
|
||||
if (rt == null)
|
||||
{
|
||||
rt = new ReusableThread(this);
|
||||
rt.start();
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
public synchronized void put(ReusableThread rt)
|
||||
{
|
||||
pool.addElement(rt);
|
||||
}
|
||||
|
||||
public synchronized void clean()
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
for (Enumeration e = pool.elements(); e.hasMoreElements(); )
|
||||
{
|
||||
ReusableThread rt = (ReusableThread) e.nextElement();
|
||||
if (now - rt.getLastRunTime() >= 30000)
|
||||
{
|
||||
rt.terminate();
|
||||
pool.removeElement(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +1,133 @@
|
||||
// Copyright (c) 1999 Brian Wellington ([email protected])
|
||||
// Portions Copyright (c) 1999 Network Associates, Inc.
|
||||
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An extension of a Thread that uses threads from a pool, rather than
|
||||
* allocating a new thread for each assigned task.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public class WorkerThread extends Thread {
|
||||
|
||||
private Runnable task;
|
||||
private String name;
|
||||
private Runnable task;
|
||||
private String name;
|
||||
|
||||
private static int nactive = 0;
|
||||
private static Vector list = new Vector();
|
||||
private static int max = 10;
|
||||
private static long lifetime = 900 * 1000; /* 15 minute default */
|
||||
private static int nactive = 0;
|
||||
private static Vector list = new Vector();
|
||||
private static int max = 10;
|
||||
private static long lifetime = 900 * 1000; /* 15 minute default */
|
||||
|
||||
private WorkerThread() {
|
||||
setDaemon(true);
|
||||
}
|
||||
private
|
||||
WorkerThread() {
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lifetime of an idle WorkerThread (in ms). A WorkerThread
|
||||
* will remain on the idle list for this much time before exiting. This
|
||||
* does not affect WorkerThreads currently idling.
|
||||
*/
|
||||
synchronized static void
|
||||
setLifetime(long time) {
|
||||
lifetime = time;
|
||||
}
|
||||
/**
|
||||
* Sets the lifetime of an idle WorkerThread (in ms). A WorkerThread
|
||||
* will remain on the idle list for this much time before exiting. This
|
||||
* does not affect WorkerThreads currently idling.
|
||||
*/
|
||||
synchronized static void
|
||||
setLifetime(long time) {
|
||||
lifetime = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of WorkerThreads that can exist at any given
|
||||
* time. If this value is decreased below the current number of
|
||||
* WorkerThreads, this will not take effect immediately.
|
||||
*/
|
||||
synchronized static void
|
||||
setMaxThreads(int maxThreads) {
|
||||
max = maxThreads;
|
||||
}
|
||||
/**
|
||||
* Sets the maximum number of WorkerThreads that can exist at any given
|
||||
* time. If this value is decreased below the current number of
|
||||
* WorkerThreads, this will not take effect immediately.
|
||||
*/
|
||||
synchronized static void
|
||||
setMaxThreads(int maxThreads) {
|
||||
max = maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a WorkerThread to which a task can be assigned. If an idle
|
||||
* WorkerThread is present, it is removed from the idle list and returned.
|
||||
* If not, and the maximum number of WorkerThreads has not been reached,
|
||||
* a new WorkerThread is created. If the maximum number has been reached,
|
||||
* this blocks until a WorkerThread is free.
|
||||
*/
|
||||
static WorkerThread
|
||||
getThread() {
|
||||
WorkerThread t;
|
||||
synchronized (list) {
|
||||
if (list.size() > 0) {
|
||||
t = (WorkerThread) list.firstElement();
|
||||
list.removeElement(t);
|
||||
} else if (nactive >= max) {
|
||||
while (true) {
|
||||
try {
|
||||
list.wait();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
if (list.size() == 0)
|
||||
continue;
|
||||
t = (WorkerThread) list.firstElement();
|
||||
list.removeElement(t);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
t = new WorkerThread();
|
||||
nactive++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
/**
|
||||
* Obtains a WorkerThread to which a task can be assigned. If an idle
|
||||
* WorkerThread is present, it is removed from the idle list and returned.
|
||||
* If not, and the maximum number of WorkerThreads has not been reached,
|
||||
* a new WorkerThread is created. If the maximum number has been reached,
|
||||
* this blocks until a WorkerThread is free.
|
||||
*/
|
||||
static WorkerThread
|
||||
getThread() {
|
||||
WorkerThread t;
|
||||
synchronized (list) {
|
||||
if (list.size() > 0) {
|
||||
t = (WorkerThread) list.firstElement();
|
||||
list.removeElement(t);
|
||||
}
|
||||
else if (nactive >= max) {
|
||||
while (true) {
|
||||
try {
|
||||
list.wait();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
if (list.size() == 0)
|
||||
continue;
|
||||
t = (WorkerThread) list.firstElement();
|
||||
list.removeElement(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
t = new WorkerThread();
|
||||
nactive++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a task to a WorkerThread
|
||||
*
|
||||
* @param task The task to be run
|
||||
* @param name The name of the task
|
||||
*/
|
||||
public static void
|
||||
assignThread(Runnable task, String name) {
|
||||
while (true) {
|
||||
try {
|
||||
WorkerThread t = getThread();
|
||||
synchronized (t) {
|
||||
t.task = task;
|
||||
t.name = name;
|
||||
if (!t.isAlive())
|
||||
t.start();
|
||||
else
|
||||
t.notify();
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (IllegalThreadStateException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Assigns a task to a WorkerThread
|
||||
* @param task The task to be run
|
||||
* @param name The name of the task
|
||||
*/
|
||||
public static void
|
||||
assignThread(Runnable task, String name) {
|
||||
while (true) {
|
||||
try {
|
||||
WorkerThread t = getThread();
|
||||
synchronized (t) {
|
||||
t.task = task;
|
||||
t.name = name;
|
||||
if (!t.isAlive())
|
||||
t.start();
|
||||
else
|
||||
t.notify();
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (IllegalThreadStateException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the task
|
||||
*/
|
||||
synchronized public void
|
||||
run() {
|
||||
while (true) {
|
||||
setName(name);
|
||||
try {
|
||||
task.run();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.err.println(t);
|
||||
}
|
||||
setName("idle thread");
|
||||
synchronized (list) {
|
||||
list.addElement(this);
|
||||
if (nactive >= max)
|
||||
list.notify();
|
||||
nactive--;
|
||||
}
|
||||
task = null;
|
||||
try {
|
||||
wait(lifetime);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
if (task == null) {
|
||||
list.removeElement(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Performs the task */
|
||||
synchronized public void
|
||||
run() {
|
||||
while (true) {
|
||||
setName(name);
|
||||
try {
|
||||
task.run();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.err.println(t);
|
||||
}
|
||||
setName("idle thread");
|
||||
synchronized (list) {
|
||||
list.addElement(this);
|
||||
if (nactive >= max)
|
||||
list.notify();
|
||||
nactive--;
|
||||
}
|
||||
task = null;
|
||||
try {
|
||||
wait(lifetime);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
if (task == null) {
|
||||
list.removeElement(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user