Removed: Proxy feature. It was not working since today almost every page uses HTTPS. Also Flash is limited in browsers.

This commit is contained in:
Jindra Petřík
2024-08-02 17:05:30 +02:00
parent a526fbe74a
commit 449f96942e
47 changed files with 6 additions and 5877 deletions

View File

@@ -99,6 +99,9 @@ All notable changes to this project will be documented in this file.
- Run/Debug command - executed SWF temp files (`~ffdec_run...swf` etc.) are now generated
in the directory where original SWF resides to allow loading relative assets
- [#2228] AS1/2/3 bitwise operations use hexadecimal operands
### Removed
- Proxy feature. It was not working since today almost every page uses HTTPS. Also Flash is limited in browsers.
## [20.1.0] - 2023-12-30
### Added

View File

@@ -148,7 +148,6 @@ FFDec Application is licensed under the GNU GPL v3 (GPL-3.0-or-later) licence, s
It uses modified code of these libraries:
* [JSyntaxPane] (Code editor) - Apache License 2.0
* [Muffin] (Proxy) - GPL
And links also these libraries:
@@ -169,7 +168,6 @@ See [library README](libsrc/ffdec_lib/README.md) for more info about FFDec libra
[launch4j]: http://launch4j.sourceforge.net/
[NSIS]: http://nsis.sourceforge.net/
[JSyntaxPane]: https://code.google.com/p/jsyntaxpane/
[Muffin]: https://web.archive.org/web/20171025082558/http://muffin.doit.org/ (original: http://muffin.doit.org/)
[Java Native Access - JNA]: https://github.com/twall/jna
[Insubstantial]: http://shemnon.com/speling/2011/04/insubstantial-62-release.html
[javactivex]:https://github.com/jindrapetrik/javactivex

Binary file not shown.

View File

@@ -1,16 +0,0 @@
Copyright (C) 1996-2003 Mark R. Boyns <boyns@doit.org>
Muffin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Muffin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Muffin; see the file COPYING. If not, write to the
Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

View File

@@ -1,158 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="JPProxy" default="build" basedir=".">
<description>Builds project JPProxy.</description>
<import file="buildconfig.xml"/>
<property name="DISTLIBRARIESFULLDIR" value="${DISTRIBUTIONDIR}/${DISTLIBRARIESDIR}"/>
<property name="JAVADOCFULLDIR" value="${DISTRIBUTIONDIR}/${JAVADOCDIR}"/>
<patternset id="compiler.resources">
<include name="**/?*.properties"/>
<include name="**/?*.bin"/>
<include name="**/?*.xml"/>
<include name="**/?*.txt"/>
<include name="**/?*.gif"/>
<include name="**/?*.png"/>
<include name="**/?*.jpeg"/>
<include name="**/?*.jpg"/>
<include name="**/?*.html"/>
<include name="**/?*.dtd"/>
<include name="**/?*.tld"/>
<include name="**/?*.mid"/>
<include name="**/?*.wav"/>
</patternset>
<path id="emma.lib">
<pathelement location="${TESTLIBDIR}/emma.jar"/>
<pathelement location="${TESTLIBDIR}/emma_ant.jar"/>
</path>
<taskdef resource="emma_ant.properties" classpathref="emma.lib"/>
<target name="coverage.instrumentation">
<mkdir dir="${INSTRDIR}"/>
<mkdir dir="${COVERAGEDIR}"/>
<emma>
<instr instrpath="${COMPILEDIR}" destdir="${INSTRDIR}" metadatafile="${COVERAGEDIR}/metadata.emma"
mode="copy"></instr>
</emma>
<copy todir="${INSTRDIR}">
<fileset dir="${SOURCEDIR}">
<patternset refid="compiler.resources"/>
<type type="file"/>
</fileset>
</copy>
</target>
<target name="compile">
<delete dir="${COMPILEDIR}"/>
<mkdir dir="${COMPILEDIR}"/>
<javac srcdir="${SOURCEDIR}" destdir="${COMPILEDIR}" includes="**/*.java" target="1.6" debug="true"
debuglevel="lines,vars,source">
<classpath>
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
</classpath>
</javac>
<copy todir="${COMPILEDIR}">
<fileset dir="${SOURCEDIR}">
<patternset refid="compiler.resources"/>
<type type="file"/>
</fileset>
</copy>
</target>
<target name="test" depends="clean,compile">
<delete dir="${TESTRESULTSDIR}"/>
<mkdir dir="${TESTRESULTSDIR}"/>
<mkdir dir="${TESTRESULTSDIR}/raw/"/>
<delete dir="${COMPILETESTSDIR}"/>
<mkdir dir="${COMPILETESTSDIR}"/>
<javac srcdir="${TESTDIR}" destdir="${COMPILETESTSDIR}" includes="**/*.java" target="1.6">
<classpath>
<pathelement path="${COMPILEDIR}"/>
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
<fileset dir="${TESTLIBDIR}" includes="**/*.jar"/>
</classpath>
</javac>
<antcall target="coverage.instrumentation"/>
<junit printsummary="yes" haltonfailure="yes" showoutput="yes">
<classpath>
<pathelement path="${INSTRDIR}"/>
<pathelement path="${COMPILEDIR}"/>
<pathelement path="${COMPILETESTSDIR}"/>
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
<fileset dir="${TESTLIBDIR}" includes="**/*.jar"/>
</classpath>
<jvmarg value="-Demma.coverage.out.file=${COVERAGEDIR}/coverage.emma"/>
<jvmarg value="-Demma.coverage.out.merge=true"/>
<batchtest fork="yes" todir="${TESTRESULTSDIR}/raw/">
<formatter type="xml"/>
<fileset dir="${TESTDIR}">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
<!-- JUnit report -->
<junitreport todir="${TESTRESULTSDIR}">
<fileset dir="${TESTRESULTSDIR}/raw/">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="${TESTRESULTSDIR}\html\"/>
</junitreport>
<!-- Coverage report -->
<mkdir dir="${COVERAGERESULTSDIR}"/>
<emma>
<report sourcepath="${SOURCEDIR}" depth="method">
<fileset dir="${COVERAGEDIR}">
<include name="*.emma"/>
</fileset>
<html outfile="${COVERAGERESULTSDIR}/index.html"/>
</report>
</emma>
</target>
<target name="build" depends="clean,compile">
<mkdir dir="${DISTRIBUTIONDIR}"/>
<delete dir="${DISTLIBRARIESFULLDIR}"/>
<mkdir dir="${DISTLIBRARIESFULLDIR}"/>
<copy todir="${DISTLIBRARIESFULLDIR}">
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
</copy>
<pathconvert pathsep=" " property="manifestClassPath">
<fileset dir="${DISTRIBUTIONDIR}" includes="${DISTLIBRARIESDIR}/**/*.*"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="${DISTLIBRARIESDIR}/*"/>
</chainedmapper>
</pathconvert>
<jar destfile="${DISTRIBUTIONDIR}/${JARFILENAME}.jar" basedir="${COMPILEDIR}">
<manifest>
<attribute name="Main-Class" value="${MAINCLASS}"/>
<attribute name="Class-Path" value="${manifestClassPath}"/>
</manifest>
</jar>
</target>
<target name="run" depends="build">
<java jar="${DISTRIBUTIONDIR}/${JARFILENAME}.jar" fork="true"/>
</target>
<target name="javadoc">
<mkdir dir="${JAVADOCFULLDIR}"/>
<javadoc sourcepath="${SOURCEDIR}" destdir="${JAVADOCFULLDIR}" windowtitle="${PROJECTNAME}"
useexternalfile="yes">
<fileset dir="${SOURCEDIR}" includes="**/*.java"/>
<classpath>
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
</classpath>
</javadoc>
</target>
<target name="clean">
<delete dir="${DISTRIBUTIONDIR}"/>
<delete dir="${COMPILETESTSDIR}"/>
<delete dir="${COMPILEDIR}"/>
<delete dir="${COVERAGEDIR}"/>
<delete dir="${TESTRESULTSDIR}"/>
</target>
</project>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="buildconfig" basedir=".">
<property name="PROJECTNAME" value="JPProxy"/>
<property name="JARFILENAME" value="jpproxy"/>
<property name="MAINCLASS" value="com.jpexs.proxy.Main"/>
<property name="SOURCEDIR" value="src"/>
<property name="TESTDIR" value="test"/>
<property name="TESTLIBDIR" value="testlib"/>
<property name="TESTRESULTSDIR" value="reports/tests"/>
<property name="COVERAGERESULTSDIR" value="reports/coverage"/>
<property name="DISTRIBUTIONDIR" value="dist"/>
<property name="COMPILEDIR" value="build/classes"/>
<property name="INSTRDIR" value="build/instr-classes"/>
<property name="COVERAGEDIR" value="coverage"/>
<property name="COMPILETESTSDIR" value="build/test"/>
<property name="LIBRARIESDIR" value="lib"/>
<property name="DISTLIBRARIESDIR" value="lib"/>
<property name="JAVADOCDIR" value="javadoc"/>
</project>

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/classes" />
<output-test url="file://$MODULE_DIR$/build/test" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,3 +0,0 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="JPProxy" default="default" basedir=".">
<description>Builds, tests, and runs the project JPProxy.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar: JAR building
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="JPProxy-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
nbbuild.xml.data.CRC32=0a5363c8
nbbuild.xml.script.CRC32=2eebe506
nbbuild.xml.stylesheet.CRC32=8064a381@1.74.2.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=0a5363c8
nbproject/build-impl.xml.script.CRC32=6f75ce45
nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48

View File

@@ -1,74 +0,0 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=JPProxy
application.vendor=JPEXS
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
buildfile=nbbuild.xml
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/JPProxy.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.jpproxy-src=src
includes=**
jar.compress=false
javac.classpath=
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=\
${javac.classpath}
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=com.jpexs.proxy.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=${file.reference.jpproxy-src}

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>JPProxy</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots/>
</data>
</configuration>
</project>

View File

@@ -1,130 +0,0 @@
package com.jpexs.proxy;
import java.io.IOException;
import java.io.OutputStream;
public class ByteArray {
public byte[] bytes;
public int offset = 0;
/**
* Create a ByteArray with the default size.
*/
public ByteArray() {
this(512);
}
/**
* Create a ByteArray with a specific default size.
*/
public ByteArray(int size) {
bytes = new byte[size];
}
/**
* Create a ByteArray from a String.
*/
public ByteArray(String s) {
this(s.length());
append(s);
}
/**
* Create a ByteArray from an array of bytes.
*/
public ByteArray(byte[] b) {
this(b.length);
append(b);
}
/**
* Append a byte.
*/
public void append(byte ch) {
if (offset == bytes.length) {
byte[] tmpbytes = bytes;
bytes = new byte[tmpbytes.length * 2];
System.arraycopy(tmpbytes, 0, bytes, 0, offset);
}
bytes[offset++] = ch;
}
/**
* Append a ByteArray.
*/
public void append(ByteArray b) {
if (bytes.length - offset < b.length()) {
byte[] tmpbytes = bytes;
bytes = new byte[tmpbytes.length + b.length()];
System.arraycopy(tmpbytes, 0, bytes, 0, offset);
}
System.arraycopy(b.bytes, 0, bytes, offset, b.length());
offset += b.length();
}
/**
* Append an array of bytes.
*/
public void append(byte[] b) {
if (bytes.length - offset < b.length) {
byte[] tmpbytes = bytes;
bytes = new byte[tmpbytes.length + b.length];
System.arraycopy(tmpbytes, 0, bytes, 0, offset);
}
System.arraycopy(b, 0, bytes, offset, b.length);
offset += b.length;
}
/**
* Append a String.
*/
public void append(String s) {
append(s.getBytes());
}
/**
* Convert to String.
*/
public String toString() {
return new String(bytes, 0, offset);
}
/**
* Return the bytes.
*/
public byte[] getBytes() {
return bytes;
}
public void writeTo(OutputStream out)
throws IOException {
out.write(bytes, 0, offset);
}
public byte get(int i) {
return bytes[i];
}
/**
* Return the number of bytes.
*/
public int length() {
return offset;
}
public void erase() {
offset = 0;
}
public void chop() {
chop(1);
}
public void chop(int i) {
offset -= i;
if (offset < 0) {
offset = 0;
}
}
}

View File

@@ -1,21 +0,0 @@
package com.jpexs.proxy;
import java.io.InputStream;
/**
* Interface to catch contentTypes
*
* @author JPEXS
*/
public interface CatchedListener {
/**
* Method called when specified contentType is received
*
* @param contentType Content type
* @param url URL of the method
* @param data Data stream
* @return replacement data
*/
public byte[] catched(String contentType, String url, InputStream data);
}

View File

@@ -1,6 +0,0 @@
package com.jpexs.proxy;
public interface Cleanable {
public void clean();
}

View File

@@ -1,45 +0,0 @@
package com.jpexs.proxy;
import java.io.*;
import java.net.Socket;
public class Client extends Connection {
@Override
public void promoteToServerSSL() {
super.promoteToServerSSL();
in = new BufferedInputStream(in);
out = new BufferedOutputStream(out);
}
/**
* 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);
}
/**
* Read a Request.
*
* @returns a Request.
* @see 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());
}
}

View File

@@ -1,154 +0,0 @@
package com.jpexs.proxy;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
class Connection {
Socket socket = null;
InputStream in = null;
OutputStream out = null;
static SSLSocketFactory sf;
static {
String ksName = ProxyConfig.httpsKeyStoreFile;
if (ksName != null) {
char[] ksPass = ProxyConfig.httpsKeyStorePass.toCharArray();
char[] ctPass = ProxyConfig.httpsKeyPass.toCharArray();
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(ksName), ksPass);
KeyManagerFactory kmf
= KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, ctPass);
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
sf = sc.getSocketFactory();
} catch (Exception ex) {
}
}
}
public void promoteToClientSSL() {
SSLSocketFactory f = (SSLSocketFactory) SSLSocketFactory.getDefault();
try {
socket = (SSLSocket) f.createSocket(socket, null, socket.getPort(), false);
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException ex) {
}
}
public void promoteToServerSSL() {
try {
socket = sf.createSocket(socket, null, socket.getPort(), false);
((SSLSocket) socket).setUseClientMode(false);
} catch (Exception ex) {
ex.printStackTrace();
}
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException ex) {
}
}
/**
* Create a Connection from a Socket.
*
* @param socket a socket
*/
Connection(Socket socket) throws IOException {
this.socket = socket;
in = socket.getInputStream();
out = socket.getOutputStream();
}
/**
* Create a Connection from a hostname and port.
*
* @param host remote hostname
* @param port remote port
*/
Connection(String host, int port) throws IOException {
this(new Socket(InetAddress.getByName(host), port));
}
Connection() {
}
/**
* Return the input stream.
*/
InputStream getInputStream() {
return in;
}
/**
* Return the output stream.
*/
OutputStream getOutputStream() {
return out;
}
void setInputStream(InputStream in) {
this.in = in;
}
void setOutputStream(OutputStream out) {
this.out = out;
}
/**
* Close the connection.
*/
void close() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
public Socket getSocket() {
return socket;
}
public InetAddress getInetAddress() {
return socket.getInetAddress();
}
public int getPort() {
return socket.getPort();
}
public String toString() {
return getInetAddress().getHostAddress() + ":" + getPort();
}
public void setTimeout(int timeout)
throws SocketException {
socket.setSoTimeout(timeout);
}
}

View File

@@ -1,33 +0,0 @@
package com.jpexs.proxy;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.SocketException;
class Copy implements Runnable {
InputStream in = null;
OutputStream out = null;
Copy(InputStream in, OutputStream out) {
this.in = in;
this.out = out;
}
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 (SocketException e) {
} catch (IOException e) {
//Ignore errors
}
}
}

View File

@@ -1,665 +0,0 @@
package com.jpexs.proxy;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import javax.net.ssl.SSLHandshakeException;
class Handler implements Runnable {
static final boolean DEBUG = false;
Client client = null;
Socket socket = null;
Request request = null;
Reply reply = null;
HttpRelay http = null;
int currentLength = -1;
int contentLength = -1;
long idle = 0;
double bytesPerSecond = 0;
List<Replacement> replacements;
CatchedListener catchedListener;
List<String> catchedContentTypes;
ReplacedListener replacedListener;
static int curId = 0;
int id;
/**
* Create a Handler.
*/
Handler(Socket socket, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
curId++;
id = curId;
this.socket = socket;
this.replacements = replacements;
this.catchedListener = catchedListener;
this.catchedContentTypes = catchedContentTypes;
this.replacedListener = replacedListener;
}
/**
* Close all connections associated with this handler.
*/
synchronized void close() {
if (client != null) {
client.close();
client = null;
}
if (http != null) {
http.close();
http = null;
}
}
/**
* Flush all data to the client.
*/
void flush() {
if (client != null) {
try {
client.getOutputStream().flush();
} catch (IOException e) {
}
}
}
public void run() {
boolean keepAlive = false;
Exception reason = null;
Thread.currentThread().setName("Handler("
+ socket.getInetAddress().getHostAddress()
+ ")");
try {
client = new Client(socket);
client.setTimeout(ProxyConfig.readTimeout);
} catch (IOException e) {
return;
}
try {
boolean secure = false;
int securePort = 443;
String secureServer = "";
do {
request = null;
reply = null;
idle = System.currentTimeMillis();
try {
request = client.read();
if (secure) {
request.addSecureHostToURL(secureServer);
}
} catch (SSLHandshakeException she) {
she.printStackTrace();
break;
} catch (IOException e) {
break;
}
if (request.getCommand().equals("CONNECT")) {
secureServer = request.getHost();
securePort = request.getPort();
if ((ProxyConfig.httpsMode == ProxyConfig.HTTPS_FILTER) || ((ProxyConfig.httpsMode == ProxyConfig.HTTPS_FILTERLIST) && (ProxyConfig.enabledHttpsServers.contains(secureServer)))) {
secure = true;
reply = new Reply();
reply.statusLine = "HTTP/1.0 200 Connection established";
reply.setHeaderField("Proxy-agent", ProxyConfig.appName);
try {
client.write(reply);
} catch (IOException ex) {
}
client.promoteToServerSSL();
keepAlive = true;
continue;
}
}
idle = 0;
try {
keepAlive = processRequest(secure, secureServer, securePort);
} catch (IOException ioe) {
reason = ioe;
keepAlive = false;
}
if (request != null && reply != null) {
// XXX insert the number of bytes read into the
// reply content-length for logging.
if (reply != null && currentLength > 0) {
reply.setHeaderField("Content-length", currentLength);
}
}
} while (keepAlive);
} finally {
}
if (reason != null && reason.getMessage().indexOf("Broken pipe") == -1) {
if (client != null && request != null) {
error(client.getOutputStream(), reason, request);
}
}
close();
}
boolean processRequest(boolean secure, String secureHost, int securePort) throws IOException {
boolean keepAlive = false;
while (reply == null) {
//boolean secure = false;
boolean uncompress = false;
if (request.getCommand().equals("CONNECT")) {
secure = true;
} else if (request.getURL().startsWith("/")) {
} else if (request.getURL().startsWith("https://") && (secure)) {
} else if (!request.getURL().startsWith("http://")) {
return false;
}
/* Client wants Keep-Alive */
if (ProxyConfig.proxyKeepAlive) {
keepAlive = (request.containsHeaderField("Proxy-Connection")
&& request.getHeaderField("Proxy-Connection").equals("Keep-Alive"));
}
/* Filter the request. */
//deleted
/* None found. Use http or https relay. */
if (secure) {
http = createHttpsRelay(secureHost, securePort);
} else {
http = createHttpRelay();
}
try {
http.sendRequest(request);
if (http instanceof Http) {
((Http) http).setTimeout(ProxyConfig.readTimeout);
}
reply = http.recvReply(request);
} catch (RetryRequestException e) {
http.close();
http = null;
continue; /* XXX */
}
/* Guess content-type if there aren't any headers.
Probably an upgraded HTTP/0.9 reply. */
if (reply.headerCount() == 0) {
String url = request.getURL();
if (url.endsWith("/")
|| url.endsWith(".html") || url.endsWith(".htm")) {
reply.setHeaderField("Content-type", "text/html");
}
}
/* Filter the reply. */
if (false) {
/* uncompress gzip encoded html so it can be filtered */
if (!ProxyConfig.dontUncompress
&& "text/html".equals(reply.getHeaderField("Content-type"))) {
String encoding = reply.getHeaderField("Content-Encoding");
if (encoding != null && encoding.indexOf("gzip") != -1) {
reply.removeHeaderField("Content-Encoding");
reply.removeHeaderField("Content-length");
uncompress = true;
}
}
//filter(reply);
}
if (request.containsHeaderField("Connection") && (request.getHeaderField("Connection").toLowerCase().equals("keep-alive")) && reply.containsHeaderField("Connection")
&& reply.getHeaderField("Connection").equals("Keep-Alive")) {
keepAlive = true;
}
reply.removeHeaderField("Proxy-Connection");
if (keepAlive && reply.containsHeaderField("Content-length")) {
reply.setHeaderField("Proxy-Connection", "Keep-Alive");
} else {
keepAlive = false;
}
currentLength = -1;
contentLength = -1;
try {
contentLength = Integer.parseInt(reply.getHeaderField("Content-length"));
} catch (NumberFormatException e) {
}
if (http instanceof HttpsThrough) {
HttpsThrough https = (HttpsThrough) http;
int timeout = ProxyConfig.readTimeout;
client.write(reply);
try {
client.setTimeout(timeout);
https.setTimeout(timeout);
Copy cp = new Copy(client.getInputStream(), https.getOutputStream());
ReusableThread thread = Server.getThread();
thread.setRunnable(cp);
flushCopy(https.getInputStream(), client.getOutputStream(), -1, true);
client.close();
} catch (InterruptedIOException iioe) {
// ignore socket timeout exceptions
}
} else if (reply.hasContent()) {
try {
processContent(uncompress);
} catch (IOException e) {
if (http instanceof Http) {
((Http) http).reallyClose();
} else {
http.close();
}
http = null;
client.close();
client = null;
throw e;
//return false; /* XXX */
}
/* Document contains no data. */
if (contentLength == 0) {
client.close();
}
} else {
client.write(reply);
}
http.close();
}
return keepAlive;
}
HttpRelay createHttpsRelay(String secureHost, int securePort) throws IOException {
HttpRelay http;
if ((ProxyConfig.httpsMode == ProxyConfig.HTTPS_FILTER) || ((ProxyConfig.httpsMode == ProxyConfig.HTTPS_FILTERLIST) && (ProxyConfig.enabledHttpsServers.contains(secureHost)))) {
if (ProxyConfig.useHTTPSProxy) {
http = Https.open(ProxyConfig.httpsProxyHost, ProxyConfig.httpsProxyPort, true);
Request connectReq = new Request(null);
connectReq.setStatusLine("CONNECT " + secureHost + ":" + securePort + " HTTP/1.1");
connectReq.setCommand("CONNECT");
connectReq.setURL(secureHost + ":" + securePort);
connectReq.setProtocol("HTTP/1.1");
try {
http.sendRequest(connectReq);
Reply rep = http.recvReply(connectReq);
} catch (RetryRequestException ex) {
}
((Https) http).promoteToClientSSL();
} else {
http = Https.open(secureHost, securePort, false);
((Https) http).promoteToClientSSL();
}
/*http = new Http(request.getHost(),request.getPort(),ProxyConfig.useHTTPSProxy);
if(ProxyConfig.useHTTPSProxy){
Request connectReq=new Request(client);
connectReq.setCommand("CONNECT");
connectReq.setURL(secureHost+":"+securePort);
connectReq.setProtocol("HTTP/1.1");
try {
http.sendRequest(connectReq);
http.recvReply(connectReq);
} catch (RetryRequestException ex) {
}
}
((Http)http).promoteToClientSSL();*/
} else {
if (ProxyConfig.useHTTPSProxy) {
http = new HttpsThrough(ProxyConfig.httpsProxyHost,
ProxyConfig.httpsProxyPort,
true);
} else {
http = new HttpsThrough(secureHost, securePort);
}
}
return http;
}
HttpRelay createHttpRelay() throws IOException {
HttpRelay http;
if (ProxyConfig.useHTTPProxy) {
http = Http.open(ProxyConfig.httpProxyHost,
ProxyConfig.httpProxyPort,
true);
} else {
http = Http.open(request.getHost(), request.getPort());
}
return http;
}
InputStream readChunkedTransfer(InputStream in) throws IOException {
ByteArrayOutputStream chunks = new ByteArrayOutputStream(8192);
int size = 0;
contentLength = 0;
while ((size = reply.getChunkSize(in)) > 0) {
contentLength += size;
copy(in, chunks, size, true);
reply.readLine(in);
}
reply.getChunkedFooter(in);
reply.removeHeaderField("Transfer-Encoding");
reply.setHeaderField("Content-length", contentLength);
return new ByteArrayInputStream(chunks.toByteArray());
}
private static DateFormat httpDateFormat() {
DateFormat httpDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
httpDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
return httpDateFormat;
}
void disableReplyCaching() {
reply.removeHeaderField("Cache-Control");
reply.removeHeaderField("Last-Modified");
reply.removeHeaderField("Expires");
reply.removeHeaderField("Date");
reply.removeHeaderField("ETag");
reply.removeHeaderField("Pragma");
reply.setHeaderField("Pragma", "no-cache");
reply.setHeaderField("Cache-Control", "no-cache, must-revalidate");
Calendar now = Calendar.getInstance();
reply.setHeaderField("Expires", httpDateFormat().format(now.getTime()));//"Sat, 26 Jul 1997 05:00:00 GMT");
reply.setHeaderField("Last-Modified", "Sat, 26 Jul 1997 05:00:00 GMT");
}
void processContent(boolean uncompress) throws IOException {
InputStream in;
boolean chunked = false;
if (reply.containsHeaderField("Transfer-Encoding")
&& reply.getTransferEncoding().equals("chunked")) {
in = readChunkedTransfer(reply.getContent());
chunked = true;
} else {
in = reply.getContent();
}
if (in == null) {
return;
} else if (uncompress) {
in = new GZIPInputStream(in);
}
String url = request.getURL();
boolean replaced = false;
for (Replacement r : replacements) {
if (r.matches(url)) {
r.lastAccess = Calendar.getInstance();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
FileInputStream fis = new FileInputStream(r.targetFile);
byte[] buf = new byte[4096];
int pos = 0;
while ((pos = fis.read(buf)) > 0) {
buffer.write(buf, 0, pos);
}
fis.close();
buffer.close();
} catch (IOException ex) {
}
byte[] bytes = buffer.toByteArray();
contentLength = bytes.length;
reply.setHeaderField("Content-length", contentLength);
disableReplyCaching();
client.write(reply);
copy(new ByteArrayInputStream(bytes),
client.getOutputStream(), contentLength, false);
replaced = true;
if (replacedListener != null) {
replacedListener.replaced(r, request.getURL(), reply.getContentType());
}
break;
}
}
if (!replaced) {
String contentType = reply.getHeaderField("Content-type");
if (reply.getStatusCode() == 200) {
if (contentType != null) {
for (String ct : catchedContentTypes) {
String convContentType = contentType;
if (convContentType.contains(";")) {
convContentType = convContentType.substring(0, convContentType.indexOf(";"));
}
if (ct.toLowerCase().equals(convContentType.toLowerCase())) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(in, baos, contentLength, true);
byte[] data = baos.toByteArray();
if (catchedListener != null) {
byte[] newData = catchedListener.catched(ct, request.getURL(), new ByteArrayInputStream(data));
if (newData != null) {
data = newData;
contentLength = data.length;
reply.setHeaderField("Content-length", contentLength);
}
}
in = new ByteArrayInputStream(data);
disableReplyCaching();
break;
}
}
}
}
client.write(reply);
copy(in, client.getOutputStream(), contentLength, true);
}
}
/**
* Return the content length.
*/
int getTotalBytes() {
return contentLength > 0 ? contentLength : 0;
}
/**
* Return the number of bytes read so far.
*/
int getCurrentBytes() {
return currentLength > 0 ? currentLength : 0;
}
/**
* Send a error message to the client.
*
* @param out client
* @param e exception that occurred
* @param r request
*/
void error(OutputStream out, Exception e, Request r) {
StringBuffer buf = new StringBuffer();
buf.append("While trying to retrieve the URL: <a href=\"" + r.getURL() + "\">" + r.getURL() + "</a>\r\n");
buf.append("<p>\r\nThe following error was encountered:\r\n<p>\r\n");
buf.append("<ul><li>" + e.toString() + "</ul>\r\n");
String s = new HttpError(400, buf.toString()).toString();
try {
out.write(s.getBytes(), 0, s.length());
out.flush();
} catch (Exception ex) {
}
}
/**
* Copy in to out.
*
* @param in InputStream
* @param out OutputStream
* @param monitored Update the Monitor
*/
void copy(InputStream in, OutputStream out, int length, boolean monitored)
throws IOException {
if (length == 0) {
return;
}
int n;
byte[] buffer = new byte[8192];
long start = System.currentTimeMillis();
long now = 0, then = start;
bytesPerSecond = 0;
if (monitored) {
currentLength = 0;
}
for (;;) {
n = (length > 0) ? Math.min(length, buffer.length) : buffer.length;
n = in.read(buffer, 0, n);
if (n < 0) {
break;
}
out.write(buffer, 0, n);
if (monitored) {
currentLength += n;
}
now = System.currentTimeMillis();
bytesPerSecond = currentLength / ((now - start) / 1000.0);
// flush after 1 second
if (now - then > 1000) {
out.flush();
}
if (length != -1) {
length -= n;
if (length == 0) {
break;
}
}
then = now;
}
out.flush();
}
/**
* Copy in to out.
*
* @param in InputStream
* @param out OutputStream
* @param monitored Update the Monitor
*/
void flushCopy(InputStream in, OutputStream out, int length, boolean monitored)
throws IOException {
if (length == 0) {
return;
}
int n;
byte[] buffer = new byte[8192];
long start = System.currentTimeMillis();
bytesPerSecond = 0;
if (monitored) {
currentLength = 0;
}
for (;;) {
n = (length > 0) ? Math.min(length, buffer.length) : buffer.length;
n = in.read(buffer, 0, n);
if (n < 0) {
break;
}
out.write(buffer, 0, n);
out.flush();
if (monitored) {
currentLength += n;
}
bytesPerSecond = currentLength / ((System.currentTimeMillis() - start) / 1000.0);
if (length != -1) {
length -= n;
if (length == 0) {
break;
}
}
}
out.flush();
}
/**
* Return a string represenation of the hander's state.
*/
public String toString() {
StringBuffer str = new StringBuffer();
str.append("CLIENT ");
str.append(socket.getInetAddress().getHostAddress());
str.append(":");
str.append(socket.getPort());
str.append(" - ");
if (request == null) {
str.append("idle " + ((System.currentTimeMillis() - idle) / 1000.0) + " sec");
} else {
if (reply != null && currentLength > 0) {
str.append("(");
str.append(currentLength);
if (contentLength > 0) {
str.append("/");
str.append(contentLength);
}
str.append(" ");
str.append(((int) bytesPerSecond / 1024) + " kB/s");
str.append(") ");
}
str.append(request.getURL());
}
return str.toString();
}
}

View File

@@ -1,284 +0,0 @@
package com.jpexs.proxy;
import java.io.IOException;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
class Http extends HttpConnection {
/* 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;
boolean proxy = false;
boolean persistent = false;
boolean closed = false;
long idle = 0;
Vector queue = new Vector();
public Http(String host, int port) throws IOException {
this(host, port, false);
}
public Http(String host, int port, boolean isProxy) throws IOException {
super(host, port);
this.host = host;
this.port = port;
this.proxy = isProxy;
}
public 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;
throw new RetryRequestException();
}
throw e;
}
}
public synchronized Reply recvReply(Request request)
throws IOException, RetryRequestException {
while (queue.firstElement() != request) {
try {
wait();
} catch (InterruptedException e) {
}
}
if (closed) {
throw new RetryRequestException();
}
try {
return recv();
} catch (IOException e) {
if (persistent) {
persistent = false;
throw new RetryRequestException();
}
throw e;
}
}
public void reallyClose() {
persistent = false;
close();
}
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);
notify();
}
}
private void send(Request request) throws IOException {
/* Prepare HTTP/1.1 request */
request.removeHeaderField("Proxy-Connection");
if (!proxy) {
if (request.containsHeaderField("Connection") && (request.getHeaderField("Connection").toLowerCase().equals("keep-alive"))) {
} else {
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();
request.write(getOutputStream());
/* flush? */
request.statusLine = oldStatusLine;
}
}
private Reply recv() throws IOException {
Reply reply = new Reply(getInputStream());
reply.read();
String conn = reply.getHeaderField("Connection");
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();
}
return reply;
}
protected boolean isBusy() {
return queue.size() >= MAX_PENDING_REQUESTS;
}
protected boolean isPersistent() {
return persistent;
}
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 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 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 */ {
http.persistent = false;
http.close();
}
}
}
}
static Http open(String host, int port, boolean isProxy)
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);
/* find an http connection that isn't busy */
if (pick.isPersistent() && !pick.isBusy()) {
http = pick;
break;
}
}
if (http != null) {
http.idle = 0;
}
}
}
if (http == null) {
http = new Http(host, port, isProxy);
cacheInsert(host, port, http);
}
return http;
}
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 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();
}
}

View File

@@ -1,49 +0,0 @@
package com.jpexs.proxy;
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);
}
HttpConnection(Socket s) throws IOException {
super(s);
}
public void sendRequest(Request request)
throws IOException, RetryRequestException {
request.write(getOutputStream());
}
public Reply recvReply(Request request)
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 InputStream getInputStream() {
return super.getInputStream();
}
public OutputStream getOutputStream() {
return super.getOutputStream();
}
public void close() {
super.close();
}
}

View File

@@ -1,62 +0,0 @@
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();
}
}

View File

@@ -1,14 +0,0 @@
package com.jpexs.proxy;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
public interface HttpRelay {
void sendRequest(Request request) throws IOException, RetryRequestException;
Reply recvReply(Request request) throws IOException, RetryRequestException;
void close();
}

View File

@@ -1,127 +0,0 @@
package com.jpexs.proxy;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
*
* @author JPEXS
*/
public class Https extends Http {
/* 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();
public Https(String host, int port) throws IOException {
this(host, port, false);
}
public Https(String host, int port, boolean isProxy) throws IOException {
super(host, port, isProxy);
}
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 boolean cacheContains(Https 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, Https 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, Https 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++) {
Https http = (Https) v.elementAt(i);
if (http.idle > 0 && now - http.idle > 30000) /* 30 seconds */ {
http.persistent = false;
http.close();
}
}
}
}
static Https open(String host, int port, boolean isProxy)
throws IOException {
Https http = null;
synchronized (httpLock) {
Vector v = cacheLookup(host, port);
if (v != null) {
for (int i = 0; i < v.size(); i++) {
Https pick = (Https) v.elementAt(i);
/* find an http connection that isn't busy */
if (pick.isPersistent() && !pick.isBusy()) {
http = pick;
break;
}
}
if (http != null) {
http.idle = 0;
}
}
}
if (http == null) {
http = new Https(host, port, isProxy);
cacheInsert(host, port, http);
}
return http;
}
static Https 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 synchronized void clean() {
cacheClean();
}
}

View File

@@ -1,39 +0,0 @@
package com.jpexs.proxy;
import java.io.IOException;
class HttpsThrough extends HttpConnection {
boolean proxy = false;
HttpsThrough(String host, int port) throws IOException {
super(host, port);
}
HttpsThrough(String host, int port, boolean isProxy) throws IOException {
this(host, port);
proxy = isProxy;
}
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;
}
}

View File

@@ -1,34 +0,0 @@
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) {
}
for (Enumeration e = cleanable.elements();
e.hasMoreElements();) {
((Cleanable) e.nextElement()).clean();
}
Http.clean();
}
}
}

View File

@@ -1,35 +0,0 @@
package com.jpexs.proxy;
class Key {
private String name = null;
/**
* Create a Key.
*/
Key(String name) {
this.name = name;
}
/**
* Return a lowercase hashCode.
*/
public int hashCode() {
String s = name.toLowerCase();
return s.hashCode();
}
/**
* Return a lowercase equals.
*/
public boolean equals(Object obj) {
return name.equalsIgnoreCase(obj.toString());
}
/**
* Return the key.
*/
public String toString() {
return name;
}
}

View File

@@ -1,65 +0,0 @@
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 byte[] catched(String contentType, String url, InputStream data) {
return null;
}
}, 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);
}
}
});
}
}

View File

@@ -1,242 +0,0 @@
package com.jpexs.proxy;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import java.io.*;
public abstract class Message {
/**
* Hashtable used to store message headers.
*/
private Hashtable headers = new Hashtable(33);
/**
*
*/
String statusLine = null;
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);
}
/**
* 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);
}
}
}
public int headerCount() {
return headers.size();
}
/**
* Set the Status line.
*/
public void setStatusLine(String l) {
statusLine = l;
}
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 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);
}
/**
* 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);
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, int index) {
setHeaderField(name, getHeaderField(name, index) + value, index);
}
public void removeHeaderField(String name) {
headers.remove(new Key(name));
}
/**
* Return whether or not a header exists.
*
* @param name header name
*/
public boolean containsHeaderField(String name) {
return headers.containsKey(new Key(name));
}
/**
* @return an Enumeration of Strings
*/
public Enumeration getHeaders() {
Vector v = new Vector();
for (Enumeration e = headers.keys(); e.hasMoreElements();) {
v.addElement(e.nextElement().toString());
}
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);
return buf;
}
private ByteArray toByteArray() {
return toByteArray(CRLF);
}
private ByteArray toByteArray(String sep) {
return toByteArray(sep.getBytes());
}
public String toString() {
return toByteArray().toString();
}
public String toString(String sep) {
return toByteArray(sep).toString();
}
public void write(OutputStream out)
throws IOException {
toByteArray().writeTo(out);
out.flush();
}
}

View File

@@ -1,43 +0,0 @@
package com.jpexs.proxy;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
public class ProxyConfig {
public static boolean dontLogFilters = false;
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 final int HTTPS_PASSTHRU = 0;
public static final int HTTPS_FILTER = 1;
public static final int HTTPS_FILTERLIST = 2;
public static int httpsMode = HTTPS_PASSTHRU;
public static List<String> enabledHttpsServers = new ArrayList<String>();
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;
public static String httpsKeyStoreFile = null;
public static String httpsKeyStorePass = null;
public static String httpsKeyPass = null;
}

View File

@@ -1,6 +0,0 @@
package com.jpexs.proxy;
public interface ReplacedListener {
public void replaced(Replacement replacement, String url, String contentType);
}

View File

@@ -1,80 +0,0 @@
package com.jpexs.proxy;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.regex.Pattern;
/**
* Replacement of URL with local file
*/
public class Replacement {
/**
* URL pattern, can contain * wild-cards
*/
public String urlPattern;
/**
* Filename to replace content with
*/
public String targetFile;
/**
* Date of last accesing this url
*/
public Calendar lastAccess;
/**
* Constructor
*
* @param urlPattern URL pattern, can contain * wild-cards
* @param targetFile Filename to replace content with
*/
public Replacement(String urlPattern, String targetFile) {
this.urlPattern = urlPattern;
this.targetFile = targetFile;
}
/**
* Returns true when urlPattern matches specified url
*
* @param url Url to test match
* @return True when matches
*/
public boolean matches(String url) {
String pat = Pattern.quote(urlPattern);
pat = pat.replace("*", "\\E.*\\Q");
return Pattern.matches(pat, url);
}
private static String byteCountStr(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit) {
return bytes + " B";
}
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
/**
* Returns a string representation of the object.
*
* @return a string representation of the object.
*/
@Override
public String toString() {
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
long size = new File(targetFile).length();
String sizeS = byteCountStr(size, false);
while (sizeS.length() < 12) {
sizeS = " " + sizeS;
}
if (lastAccess == null) {
return " " + " | " + sizeS + " | " + urlPattern;
} else {
return format.format(lastAccess.getTime()) + " | " + sizeS + " | " + urlPattern;
}
}
}

View File

@@ -1,202 +0,0 @@
package com.jpexs.proxy;
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;
public class Reply extends Message {
InputStream in = null;
int statusCode = -1;
public Reply() {
}
public Reply(InputStream in) {
setContent(in);
}
public void setContent(InputStream in) {
this.in = 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;
}
}
public boolean hasContent() {
switch (getStatusCode()) {
case 204:
case 304:
return false;
default:
return true;
}
}
public String getProtocol() {
StringTokenizer st = new StringTokenizer(statusLine);
String protocol = (String) st.nextToken();
return protocol;
}
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) {
System.out.println("Malformed or missing status code");
statusCode = 0;
}
}
return statusCode;
}
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 getContentType() {
Hashtable table = headerParser("Content-type");
return (String) table.get("Content-type");
}
public String getBoundary() {
Hashtable table = headerParser("Content-type");
return (String) table.get("boundary");
}
public String getTransferEncoding() {
Hashtable table = headerParser("Transfer-Encoding");
return (String) table.get("Transfer-Encoding");
}
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 getChunkedFooter(InputStream in) throws IOException {
for (;;) {
String line = readLine(in);
if (line == null) {
break;
}
int i = line.indexOf(':');
if (i == -1) {
break;
}
}
}
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;
}
}

View File

@@ -1,223 +0,0 @@
package com.jpexs.proxy;
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.Vector;
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;
public boolean hadKeepalive = false;
Request(Client c) {
client = c;
}
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();
if (!url.startsWith("http")) {
//TODO do something here
}
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) {
}
}
}
public void write(OutputStream out)
throws IOException {
super.write(out);
if (data != null) {
out.write(data);
out.flush();
}
}
public String getRequest() {
return statusLine;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public String getURL() {
return url;
}
public void setURL(String url) {
this.url = url;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void addSecureHostToURL(String host) {
url = "https://" + host + url;
}
public String getHost() {
String url = getURL();
String s;
if (url.startsWith("http://")) {
s = url.substring(7, url.indexOf('/', 7));
} else if (url.startsWith("https://")) {
s = url.substring(8, url.indexOf('/', 8));
} 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 int getPort() {
int port = 80;
String url = getURL();
String s;
if (url.startsWith("http://")) {
s = url.substring(7, url.indexOf('/', 7));
} else if (url.startsWith("https://")) {
s = url.substring(8, url.indexOf('/', 8));
port = 443;
} 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) {
}
}
return port;
}
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 Client getClient() {
return client;
}
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();
}
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 getLogEntries(String header) {
return log != null ? ((Vector) log.get(header)).elements() : null;
}
}

View File

@@ -1,12 +0,0 @@
package com.jpexs.proxy;
class RetryRequestException extends Exception {
RetryRequestException() {
super();
}
RetryRequestException(String message) {
super(message);
}
}

View File

@@ -1,57 +0,0 @@
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);
}
}
}
}

View File

@@ -1,139 +0,0 @@
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();
stopping = false;
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) {
stopping = true;
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();
}
}
}

View File

@@ -1,45 +0,0 @@
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);
}
}
}
}

View File

@@ -1,134 +0,0 @@
package com.jpexs.proxy;
import java.util.*;
public class WorkerThread extends Thread {
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
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 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;
}
/**
* 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;
}
}
}
}

View File

@@ -1914,17 +1914,8 @@ public class CommandLineArgumentParser {
}
private static void parseProxy(Stack<String> args) {
int port = 55555;
String portStr = args.peek();
if (portStr != null && portStr.startsWith("-P")) {
args.pop();
try {
port = Integer.parseInt(portStr.substring(2));
} catch (NumberFormatException nex) {
System.err.println("Bad port number");
}
}
Main.startProxy(port);
System.err.println("Proxy functionalit was REMOVED");
System.exit(1);
}
private static List<String> parseSelectClass(Stack<String> args) {

View File

@@ -49,7 +49,6 @@ import com.jpexs.decompiler.flash.gfx.GfxConvertor;
import com.jpexs.decompiler.flash.gui.debugger.DebugAdapter;
import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools;
import com.jpexs.decompiler.flash.gui.pipes.FirstInstance;
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
@@ -78,19 +77,12 @@ import com.sun.jna.Platform;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinReg;
import java.awt.AWTException;
import java.awt.Component;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -143,7 +135,6 @@ import java.util.logging.SimpleFormatter;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
@@ -159,8 +150,6 @@ public class Main {
public static final String IMPORT_ASSETS_SEPARATOR = "{*sep*}";
protected static ProxyFrame proxyFrame;
private static List<OpenableSourceInfo> sourceInfos = new ArrayList<>();
public static LoadingDialog loadingDialog;
@@ -842,24 +831,6 @@ public class Main {
return working;
}
public static void startProxy(int port) {
if (proxyFrame == null) {
proxyFrame = new ProxyFrame(mainFrame);
}
proxyFrame.setPort(port);
addTrayIcon();
switchProxy();
}
public static void showProxy() {
if (proxyFrame == null) {
proxyFrame = new ProxyFrame(mainFrame);
}
proxyFrame.setVisible(true);
proxyFrame.setState(Frame.NORMAL);
}
public static void continueWork(String name) {
continueWork(name, -1);
}
@@ -1762,11 +1733,6 @@ public class Main {
}
}
}
if (proxyFrame != null) {
proxyFrame.setVisible(false);
proxyFrame.dispose();
proxyFrame = null;
}
if (loadFromMemoryFrame != null) {
loadFromMemoryFrame.setVisible(false);
loadFromMemoryFrame.dispose();
@@ -2938,79 +2904,6 @@ public class Main {
}
}
public static void switchProxy() {
proxyFrame.switchState();
if (stopMenuItem != null) {
if (proxyFrame.isRunning()) {
stopMenuItem.setLabel(AppStrings.translate("proxy.stop"));
} else {
stopMenuItem.setLabel(AppStrings.translate("proxy.start"));
}
}
}
public static void addTrayIcon() {
if (trayIcon != null) {
return;
}
if (SystemTray.isSupported()) {
SystemTray tray = SystemTray.getSystemTray();
trayIcon = new TrayIcon(View.loadImage("proxy16"), ApplicationInfo.VENDOR + " " + ApplicationInfo.SHORT_APPLICATION_NAME + " " + AppStrings.translate("proxy"));
trayIcon.setImageAutoSize(true);
PopupMenu trayPopup = new PopupMenu();
ActionListener trayListener = new ActionListener() {
/**
* Invoked when an action occurs.
*/
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("EXIT")) {
Main.exit();
}
if (e.getActionCommand().equals("SHOW")) {
Main.showProxy();
}
if (e.getActionCommand().equals("SWITCH")) {
Main.switchProxy();
}
}
};
MenuItem showMenuItem = new MenuItem(AppStrings.translate("proxy.show"));
showMenuItem.setActionCommand("SHOW");
showMenuItem.addActionListener(trayListener);
trayPopup.add(showMenuItem);
stopMenuItem = new MenuItem(AppStrings.translate("proxy.start"));
stopMenuItem.setActionCommand("SWITCH");
stopMenuItem.addActionListener(trayListener);
trayPopup.add(stopMenuItem);
trayPopup.addSeparator();
MenuItem exitMenuItem = new MenuItem(AppStrings.translate("exit"));
exitMenuItem.setActionCommand("EXIT");
exitMenuItem.addActionListener(trayListener);
trayPopup.add(exitMenuItem);
trayIcon.setPopupMenu(trayPopup);
trayIcon.addMouseListener(new MouseAdapter() {
/**
* {@inheritDoc}
*/
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
Main.showProxy();
}
}
});
try {
tray.add(trayIcon);
} catch (AWTException ex) {
//ignored
}
}
}
public static List<SWF> namesToSwfs(List<String> names) {
List<SWF> ret = new ArrayList<>();
Map<String, SWF> swfs = new LinkedHashMap<>();

View File

@@ -547,18 +547,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
return false;
}
protected void showProxyActionPerformed(ActionEvent evt) {
if (Main.isWorking()) {
return;
}
if (mainFrame.getPanel().checkEdited()) {
return;
}
Main.showProxy();
}
protected boolean clearLog(ActionEvent evt) {
ErrorLogFrame.getInstance().clearLog();
return true;
@@ -1083,7 +1072,6 @@ public abstract class MainFrameMenu implements MenuBuilder {
setMenuEnabled("/tools/replace", swfSelected);
setMenuEnabled("/tools/timeline", swfSelected);
setMenuEnabled("/tools/abcExplorer", isAs3);
setMenuEnabled("/tools/showProxy", !isWorking);
setMenuEnabled("/tools/gotoDocumentClass", hasAbc);
/*setMenuEnabled("/tools/debugger/debuggerSwitch", hasAbc);
@@ -1277,7 +1265,6 @@ public abstract class MainFrameMenu implements MenuBuilder {
addToggleMenuItem("/tools/timeline", translate("menu.tools.timeline"), null, "timeline32", this::timelineActionPerformed, PRIORITY_TOP, null);
addMenuItem("/tools/abcExplorer", translate("menu.tools.abcexplorer"), "abcexplorer32", this::abcExplorerActionPerformed, PRIORITY_TOP, null, true, null, false);
addMenuItem("/tools/showProxy", translate("menu.tools.proxy"), "proxy16", this::showProxyActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
if (Platform.isWindows()) {
addMenuItem("/tools/searchMemory", translate("menu.tools.searchMemory"), "loadmemory16", this::searchMemoryActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright (C) 2010-2024 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.ApplicationInfo;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JLabel;
/**
* Frame with selection on application startServer
*
* @author JPEXS
*/
public class ModeFrame extends AppFrame {
private final JButton openButton = new JButton(translate("button.open"));
private final JButton proxyButton = new JButton(translate("button.proxy"));
private final JButton exitButton = new JButton(translate("button.exit"));
/**
* Constructor
*/
public ModeFrame() {
setSize(350, 200);
openButton.addActionListener(this::openButtonActionPerformed);
openButton.setIcon(View.getIcon("open32"));
proxyButton.addActionListener(this::proxyButtonActionPerformed);
proxyButton.setIcon(View.getIcon("proxy32"));
exitButton.addActionListener(this::exitButtonActionPerformed);
exitButton.setIcon(View.getIcon("exit32"));
setResizable(false);
Container cont = getContentPane();
cont.setLayout(new GridLayout(4, 1));
JLabel logoLabel = new JLabel();
logoLabel.setIcon(View.getIcon("logo"));
cont.add(logoLabel);
cont.add(openButton);
cont.add(proxyButton);
cont.add(exitButton);
View.centerScreen(this);
View.setWindowIcon(this);
setTitle(ApplicationInfo.shortApplicationVerName);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Main.exit();
}
});
}
private void openButtonActionPerformed(ActionEvent evt) {
setVisible(false);
if (!Main.openFileDialog()) {
setVisible(true);
}
}
private void proxyButtonActionPerformed(ActionEvent evt) {
setVisible(false);
Main.showProxy();
}
private void exitButtonActionPerformed(ActionEvent evt) {
setVisible(false);
Main.exit();
}
}

View File

@@ -28,7 +28,6 @@ import com.jpexs.decompiler.flash.gui.GraphDialog;
import com.jpexs.decompiler.flash.gui.LoadFromMemoryFrame;
import com.jpexs.decompiler.flash.gui.LoadingDialog;
import com.jpexs.decompiler.flash.gui.MainFrame;
import com.jpexs.decompiler.flash.gui.ModeFrame;
import com.jpexs.decompiler.flash.gui.NewVersionDialog;
import com.jpexs.decompiler.flash.gui.RenameDialog;
import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog;
@@ -39,7 +38,6 @@ import com.jpexs.decompiler.flash.gui.SelectLanguageDialog;
import com.jpexs.decompiler.flash.gui.abc.DeobfuscationDialog;
import com.jpexs.decompiler.flash.gui.abc.NewTraitDialog;
import com.jpexs.decompiler.flash.gui.abc.UsageFrame;
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
import com.jpexs.helpers.Helper;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
@@ -253,7 +251,6 @@ public class CheckResources {
LoadFromMemoryFrame.class,
LoadingDialog.class,
MainFrame.class,
ModeFrame.class,
NewVersionDialog.class,
RenameDialog.class,
ReplaceCharacterDialog.class,
@@ -265,8 +262,6 @@ public class CheckResources {
DeobfuscationDialog.class,
NewTraitDialog.class,
UsageFrame.class,
// Proxy
ProxyFrame.class
};
return classes;
}

View File

@@ -1,741 +0,0 @@
/*
* Copyright (C) 2010-2024 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.proxy;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.RunnableIOEx;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.AppFrame;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.FasterScrollPane;
import com.jpexs.decompiler.flash.gui.GuiAbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.MainFrame;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.ViewMessages;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.utf8.Utf8InputStreamReader;
import com.jpexs.helpers.utf8.Utf8OutputStreamWriter;
import com.jpexs.proxy.CatchedListener;
import com.jpexs.proxy.ReplacedListener;
import com.jpexs.proxy.Replacement;
import com.jpexs.proxy.Server;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
/**
* Frame with Proxy
*
* @author JPEXS
*/
public class ProxyFrame extends AppFrame implements CatchedListener, MouseListener, ReplacedListener {
private static final String REPLACEMENTS_NAME = "replacements.cfg";
private JTable replacementsTable;
private JButton switchButton = new JButton(translate("proxy.start"));
private boolean started = false;
private JTextField portField = new JTextField("55555");
private JCheckBox sniffSWFCheckBox = new JCheckBox("SWF", false);
private JCheckBox sniffOSCheckBox = new JCheckBox("OctetStream", false);
private JCheckBox sniffJSCheckBox = new JCheckBox("JS", false);
private JCheckBox sniffXMLCheckBox = new JCheckBox("XML", false);
/**
* Is server running
*
* @return True when running
*/
public boolean isRunning() {
return started;
}
/**
* Sets port for the proxy
*
* @param port Port number
*/
public void setPort(int port) {
portField.setText(Integer.toString(port));
}
private static class SizeItem implements Comparable<SizeItem> {
String file;
public SizeItem(String file) {
this.file = file;
}
@Override
public String toString() {
return Helper.byteCountStr(new File(file).length(), false);
}
@Override
public int compareTo(SizeItem o) {
return (int) (new File(file).length() - new File(o.file).length());
}
}
DefaultTableModel tableModel;
private SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
/**
* List of replacements
*/
private static List<Replacement> replacements = new ArrayList<>();
/**
* Saves replacements to file for future use
*/
private static void saveReplacements() {
String replacementsFile = getReplacementsFile();
if (replacements.isEmpty()) {
File rf = new File(replacementsFile);
if (rf.exists()) {
if (!rf.delete()) {
Logger.getLogger(ProxyFrame.class.getName()).log(Level.SEVERE, "Cannot delete replacements file");
}
}
} else {
try (PrintWriter pw = new PrintWriter(new Utf8OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(replacementsFile))))) {
for (Replacement r : replacements) {
pw.println(r.urlPattern);
pw.println(r.targetFile);
}
} catch (IOException ex) {
Logger.getLogger(ProxyFrame.class.getName()).log(Level.SEVERE, "Exception during saving replacements", ex);
}
}
}
/**
* Load replacements from file
*/
private static void loadReplacements() {
String replacementsFile = getReplacementsFile();
if (!(new File(replacementsFile)).exists()) {
return;
}
replacements = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new Utf8InputStreamReader(new FileInputStream(replacementsFile)))) {
String s;
while ((s = br.readLine()) != null) {
Replacement r = new Replacement(s, br.readLine());
replacements.add(r);
}
} catch (IOException e) {
//ignore
}
}
private static String getReplacementsFile() {
return Configuration.getFFDecHome() + REPLACEMENTS_NAME;
}
/**
* Constructor
*
* @param mainFrame Main frame
*/
public ProxyFrame(final MainFrame mainFrame) {
final String[] columnNames = new String[]{
translate("column.accessed"),
translate("column.size"),
translate("column.url")};
loadReplacements();
Object[][] data = new Object[replacements.size()][3];
for (int i = 0; i < replacements.size(); i++) {
Replacement r = replacements.get(i);
data[i][0] = r.lastAccess == null ? "" : format.format(r.lastAccess.getTime());
data[i][1] = new SizeItem(r.targetFile);
data[i][2] = r.urlPattern;
}
tableModel = new DefaultTableModel(data, columnNames) {
@Override
public Class<?> getColumnClass(int columnIndex) {
Class[] classes = new Class[]{String.class, SizeItem.class, String.class};
return classes[columnIndex];
}
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
replacementsTable = new JTable(tableModel);
DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
tcr.setHorizontalAlignment(SwingConstants.RIGHT);
replacementsTable.setDefaultRenderer(String.class, new DefaultTableCellRenderer());
replacementsTable.setDefaultRenderer(SizeItem.class, tcr);
replacementsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
replacementsTable.setRowSelectionAllowed(true);
DefaultTableColumnModel colModel = (DefaultTableColumnModel) replacementsTable.getColumnModel();
colModel.getColumn(0).setMaxWidth(100);
colModel.getColumn(1).setMaxWidth(200);
replacementsTable.setAutoCreateRowSorter(true);
replacementsTable.setAutoCreateRowSorter(false);
replacementsTable.addMouseListener(this);
replacementsTable.setFont(new Font("Monospaced", Font.PLAIN, 12));
switchButton.addActionListener(this::switchStateButtonActionPerformed);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
cnt.add(new FasterScrollPane(replacementsTable), BorderLayout.CENTER);
portField.setPreferredSize(new Dimension(80, portField.getPreferredSize().height));
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(new FlowLayout());
buttonsPanel.add(new JLabel(translate("port")));
buttonsPanel.add(portField);
buttonsPanel.add(switchButton);
cnt.add(buttonsPanel, BorderLayout.NORTH);
JPanel buttonsPanel23 = new JPanel();
buttonsPanel23.setLayout(new BoxLayout(buttonsPanel23, BoxLayout.Y_AXIS));
JPanel buttonsPanel21 = new JPanel(new FlowLayout());
JButton openButton = new JButton(translate("open"));
openButton.addActionListener(this::openButtonActionPerformed);
buttonsPanel21.add(openButton);
JButton clearButton = new JButton(translate("clear"));
clearButton.addActionListener(this::clearButtonActionPerformed);
buttonsPanel21.add(clearButton);
JButton renameButton = new JButton(translate("rename"));
renameButton.addActionListener(this::renameButtonActionPerformed);
buttonsPanel21.add(renameButton);
JButton removeButton = new JButton(translate("remove"));
removeButton.addActionListener(this::removeButtonActionPerformed);
buttonsPanel21.add(removeButton);
//JPanel buttonsPanel22 = new JPanel(new FlowLayout());
JButton copyUrlButton = new JButton(translate("copy.url"));
copyUrlButton.addActionListener(this::copyUrlButtonActionPerformed);
buttonsPanel21.add(copyUrlButton);
JButton saveAsButton = new JButton(translate("save.as"));
saveAsButton.addActionListener(this::saveAsButtonActionPerformed);
buttonsPanel21.add(saveAsButton);
JButton replaceButton = new JButton(translate("replace"));
replaceButton.addActionListener(this::replaceButtonActionPerformed);
buttonsPanel21.add(replaceButton);
JPanel buttonsPanel3 = new JPanel();
buttonsPanel3.setLayout(new FlowLayout());
buttonsPanel3.add(new JLabel(translate("sniff")));
buttonsPanel3.add(sniffSWFCheckBox);
buttonsPanel3.add(sniffOSCheckBox);
//buttonsPanel3.add(sniffJSCheckBox);
//buttonsPanel3.add(sniffXMLCheckBox);
buttonsPanel23.add(buttonsPanel21);
//buttonsPanel23.add(buttonsPanel22);
buttonsPanel23.add(buttonsPanel3);
cnt.add(buttonsPanel23, BorderLayout.SOUTH);
setSize(800, 500);
View.centerScreen(this);
View.setWindowIcon(this);
setTitle(translate("dialog.title"));
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
setVisible(false);
Main.removeTrayIcon();
if (mainFrame != null) {
if (mainFrame.isVisible()) {
return;
}
}
Main.showModeFrame();
}
/**
* Invoked when a window is iconified.
*/
@Override
public void windowIconified(WindowEvent e) {
setVisible(false);
}
});
List<Image> images = new ArrayList<>();
images.add(View.loadImage("proxy16"));
images.add(View.loadImage("proxy32"));
setIconImages(images);
}
private void open() {
View.checkAccess();
if (replacementsTable.getSelectedRow() > -1) {
Replacement r = replacements.get(replacementsTable.getRowSorter().convertRowIndexToModel(replacementsTable.getSelectedRow()));
Main.openFile(r.targetFile, r.urlPattern);
}
}
private String selectExportDir() {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("export.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
final String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
Configuration.lastExportDir.set(Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath());
return selFile;
}
return null;
}
private int[] getSelectedRows() {
int[] sel = replacementsTable.getSelectedRows();
for (int i = 0; i < sel.length; i++) {
sel[i] = replacementsTable.getRowSorter().convertRowIndexToModel(sel[i]);
}
return sel;
}
private void openButtonActionPerformed(ActionEvent evt) {
open();
}
private void saveAsButtonActionPerformed(ActionEvent evt) {
int[] sel = getSelectedRows();
if (sel.length == 1) {
Replacement r = replacements.get(sel[0]);
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Configuration.lastSaveDir.get()));
String n = r.urlPattern;
if (n.contains("?")) {
n = n.substring(0, n.indexOf('?'));
}
if (n.contains("/")) {
n = n.substring(n.lastIndexOf('/'));
}
n = Helper.makeFileName(n);
fc.setSelectedFile(new File(Configuration.lastSaveDir.get(), n));
String ext = ".swf";
final String extension = ext;
FileFilter swfFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return (f.getName().toLowerCase(Locale.ENGLISH).endsWith(extension)) || (f.isDirectory());
}
@Override
public String getDescription() {
return AppStrings.translate("filter" + extension);
}
};
fc.setFileFilter(swfFilter);
fc.setAcceptAllFileFilterUsed(true);
if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
File file = Helper.fixDialogFile(fc.getSelectedFile());
try {
Files.copy(new File(r.targetFile).toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
ViewMessages.showMessageDialog(this, translate("error.save.as") + "\r\n" + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
}
} else {
GuiAbortRetryIgnoreHandler handler = new GuiAbortRetryIgnoreHandler();
File exportDir = new File(selectExportDir());
for (int s : sel) {
final Replacement r = replacements.get(s);
String n = r.urlPattern;
if (n.contains("?")) {
n = n.substring(0, n.indexOf('?'));
}
if (n.contains("/")) {
n = n.substring(n.lastIndexOf('/'));
}
n = Helper.makeFileName(n);
int c = 2;
String n2 = n;
while (new File(exportDir, n2).exists()) {
if (n.contains(".")) {
n2 = n.substring(0, n.lastIndexOf('.')) + c + n.substring(n.lastIndexOf('.'));
c++;
} else {
n2 = n + c + ".swf";
c++;
}
}
final File outfile = new File(exportDir, n2);
try {
new RetryTask(new RunnableIOEx() {
@Override
public void run() throws IOException {
Files.copy(new File(r.targetFile).toPath(), outfile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}, handler).run();
} catch (IOException | InterruptedException ex) {
break;
}
}
}
}
private void replaceButtonActionPerformed(ActionEvent evt) {
int[] sel = getSelectedRows();
if (sel.length > 0) {
Replacement r = replacements.get(sel[0]);
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
String ext = ".swf";
final String extension = ext;
FileFilter swfFilter = new FileFilter() {
@Override
public boolean accept(File f) {
return (f.getName().toLowerCase(Locale.ENGLISH).endsWith(extension)) || (f.isDirectory());
}
@Override
public String getDescription() {
return AppStrings.translate("filter" + extension);
}
};
fc.setFileFilter(swfFilter);
fc.setAcceptAllFileFilterUsed(true);
if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File file = Helper.fixDialogFile(fc.getSelectedFile());
try {
Files.copy(file.toPath(), new File(r.targetFile).toPath(), StandardCopyOption.REPLACE_EXISTING);
tableModel.fireTableCellUpdated(sel[0], 1/*size*/);
} catch (IOException ex) {
ViewMessages.showMessageDialog(this, translate("error.replace") + "\r\n" + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
}
}
}
private void copyUrlButtonActionPerformed(ActionEvent evt) {
int[] sel = getSelectedRows();
StringBuilder copyText = new StringBuilder();
for (int sc : sel) {
Replacement r = replacements.get(sc);
if (copyText.length() > 0) {
copyText.append(System.lineSeparator());
}
copyText.append(r.urlPattern);
}
if (copyText.length() > 0) {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection stringSelection = new StringSelection(copyText.toString());
clipboard.setContents(stringSelection, null);
}
}
private void renameButtonActionPerformed(ActionEvent evt) {
int[] sel = getSelectedRows();
if (sel.length > 0) {
Replacement r = replacements.get(sel[0]);
String s = ViewMessages.showInputDialog(this, "URL", r.urlPattern);
if (s != null) {
r.urlPattern = s;
tableModel.setValueAt(s, sel[0], 2/*url*/);
}
}
}
private void clearButtonActionPerformed(ActionEvent evt) {
for (Replacement r : replacements) {
File f;
try {
f = (new File(Main.tempFile(r.targetFile)));
if (f.exists()) {
f.delete();
}
} catch (IOException ex) {
Logger.getLogger(ProxyFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
tableModel.setRowCount(0);
replacements.clear();
saveReplacements();
}
private void removeButtonActionPerformed(ActionEvent evt) {
int[] sel = getSelectedRows();
Arrays.sort(sel);
for (int i = sel.length - 1; i >= 0; i--) {
tableModel.removeRow(sel[i]);
Replacement r = replacements.remove(sel[i]);
saveReplacements();
File f = (new File(r.targetFile));
if (f.exists()) {
f.delete();
}
}
}
private void switchStateButtonActionPerformed(ActionEvent evt) {
Main.switchProxy();
}
/**
* Switch proxy state
*/
public void switchState() {
started = !started;
if (started) {
int port = 0;
try {
port = Integer.parseInt(portField.getText());
} catch (NumberFormatException nfe) {
//ignored
}
if ((port <= 0) || (port > 65535)) {
ViewMessages.showMessageDialog(this, translate("error.port"), translate("error"), JOptionPane.ERROR_MESSAGE);
started = false;
return;
}
List<String> catchedContentTypes = new ArrayList<>();
catchedContentTypes.add("application/x-shockwave-flash");
catchedContentTypes.add("application/x-javascript");
catchedContentTypes.add("application/javascript");
catchedContentTypes.add("text/javascript");
catchedContentTypes.add("application/json");
catchedContentTypes.add("text/xml");
catchedContentTypes.add("application/xml");
catchedContentTypes.add("application/octet-stream");
if (!Server.startServer(port, replacements, catchedContentTypes, this, this)) {
JOptionPane.showMessageDialog(this, translate("error.start.server").replace("%port%", "" + port), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
started = false;
return;
}
switchButton.setText(translate("proxy.stop"));
portField.setEditable(false);
} else {
Server.stopServer();
switchButton.setText(translate("proxy.start"));
portField.setEditable(true);
}
}
/**
* Mouse clicked event
*
* @param e event
*/
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() == replacementsTable) {
if (e.getClickCount() == 2) {
open();
}
}
}
/**
* Mouse pressed event
*
* @param e event
*/
@Override
public void mousePressed(MouseEvent e) {
}
/**
* Mouse released event
*
* @param e event
*/
@Override
public void mouseReleased(MouseEvent e) {
}
/**
* Mouse entered event
*
* @param e event
*/
@Override
public void mouseEntered(MouseEvent e) {
}
/**
* Mouse exited event
*
* @param e event
*/
@Override
public void mouseExited(MouseEvent e) {
}
/**
* Method called when specified contentType is received
*
* @param contentType Content type
* @param url URL of the method
* @param data Data stream
* @return replacement data
*/
@Override
public byte[] catched(String contentType, String url, InputStream data) {
boolean swfOnly = false;
if (contentType.contains(";")) {
contentType = contentType.substring(0, contentType.indexOf(';'));
}
if ((!sniffSWFCheckBox.isSelected()) && (contentType.equals("application/x-shockwave-flash"))) {
return null;
}
if ((!sniffJSCheckBox.isSelected()) && (contentType.equals("application/javascript") || contentType.equals("application/x-javascript") || contentType.equals("text/javascript") || contentType.equals("application/json"))) {
return null;
}
if ((!sniffXMLCheckBox.isSelected()) && (contentType.equals("application/xml") || contentType.equals("text/xml"))) {
return null;
}
if ((!sniffOSCheckBox.isSelected()) && (contentType.equals("application/octet-stream"))) {
return null;
}
byte[] result = null;
boolean cont = false;
for (Replacement r : replacements) {
if (r.matches(url)) {
cont = true;
break;
}
}
if (!cont) {
try {
byte[] hdr = new byte[3];
if (data.read(hdr) != 3) {
throw new IOException();
}
String shdr = new String(hdr);
if (swfOnly && ((!shdr.equals("FWS")) && (!shdr.equals("CWS")) && (!shdr.equals("ZWS")))) {
return null; //NOT SWF
}
String tempFilePath = Main.tempFile(url);
data.reset();
byte[] dataArray = Helper.readStream(data);
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(new File(tempFilePath)))) {
fos.write(dataArray);
}
result = SWFDecompilerPlugin.fireProxyFileCatched(dataArray);
Replacement r = new Replacement(url, tempFilePath);
r.lastAccess = Calendar.getInstance();
replacements.add(r);
saveReplacements();
tableModel.addRow(new Object[]{
r.lastAccess == null ? "" : format.format(r.lastAccess.getTime()),
new SizeItem(r.targetFile),
r.urlPattern
});
} catch (IOException e) {
//ignored
}
}
return result;
}
@Override
public void setVisible(boolean b) {
if (b == true) {
Main.addTrayIcon();
}
super.setVisible(b);
}
@Override
public void replaced(Replacement replacement, String url, String contentType) {
int index = replacements.indexOf(replacement);
tableModel.setValueAt(replacement.lastAccess == null ? "" : format.format(replacement.lastAccess.getTime()), index, 0);
tableModel.setValueAt(new SizeItem(replacement.targetFile), index, 1);
tableModel.setValueAt(replacement.urlPattern, index, 2);
}
}

View File

@@ -1,179 +0,0 @@
/*
* Copyright (C) 2010-2024 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.proxy;
import com.jpexs.proxy.Replacement;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
/**
* List mode for list with SWF urls
*
* @author JPEXS
*/
public class SWFListModel implements ListModel<Replacement> {
private final List<ListDataListener> listeners = new ArrayList<>();
private final List<Replacement> replacements;
/**
* Constructor
*
* @param replacements List of replacements
*/
public SWFListModel(List<Replacement> replacements) {
this.replacements = replacements;
}
/**
* Removes replacement with specified index from the list
*
* @param index Index of replacement to remove
* @return Removed replacement
*/
public Replacement removeURL(int index) {
if (index == -1) {
return null;
}
if (index < replacements.size()) {
Replacement r = replacements.remove(index);
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index));
}
return r;
}
return null;
}
/**
* Called when data in a replacement changed
*
* @param index Index of which SWF changed
*/
public void dataChanged(int index) {
if (index == -1) {
return;
}
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index));
}
}
/**
* Returns index of specified replacement
*
* @param replacement Replacement
* @return Index of -1 if not found
*/
public int indexOf(Replacement replacement) {
for (int i = 0; i < replacements.size(); i++) {
if (replacements.get(i) == replacement) {
return i;
}
}
return -1;
}
/**
* Clears url list
*/
public void clear() {
int size = replacements.size();
if (size == 0) {
return;
}
replacements.clear();
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, 0, size - 1));
}
}
/**
* Test whether the list contains url
*
* @param url URL to test
* @return True when contains
*/
public boolean contains(String url) {
for (Replacement r : replacements) {
if (r.matches(url)) {
return true;
}
}
return false;
}
/**
* Adds url to the list
*
* @param replacement URL to add
*/
public void addURL(Replacement replacement) {
int sizeBefore = replacements.size();
replacements.add(replacement);
for (ListDataListener l : listeners) {
l.intervalAdded(new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, sizeBefore, sizeBefore));
}
}
/**
* Returns size of the list
*
* @return Size of the list
*/
@Override
public int getSize() {
return replacements.size();
}
/**
* Returns element on specified index
*
* @param index Index of element
* @return Element on index
*/
@Override
public Replacement getElementAt(int index) {
return replacements.get(index);
}
/**
* Adds add list data listener
*
* @param l list data listener
*/
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
/**
* Adds remove list data listener
*
* @param l list data listener
*/
@Override
public void removeListDataListener(ListDataListener l) {
if (listeners.contains(l)) {
listeners.remove(l);
}
}
}