mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-22 01:56:54 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
lib/jpproxy.jar
BIN
lib/jpproxy.jar
Binary file not shown.
@@ -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.
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
public interface Cleanable {
|
||||
|
||||
public void clean();
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
public interface ReplacedListener {
|
||||
|
||||
public void replaced(Replacement replacement, String url, String contentType);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
class RetryRequestException extends Exception {
|
||||
|
||||
RetryRequestException() {
|
||||
super();
|
||||
}
|
||||
|
||||
RetryRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user