/* * Created on Dec 1, 2009 */ package craterstudio.indiespot.http; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; 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.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import craterstudio.bytes.Hash; import craterstudio.func.OrderComparator; import craterstudio.io.FileUtil; import craterstudio.io.Streams; import craterstudio.misc.Compression; import craterstudio.misc.Compression.ArchiveEntry; import craterstudio.text.Text; import craterstudio.util.HighLevel; import craterstudio.util.concur.SimpleCountDownLatch; import jawnae.net.http.core.HttpRequest; import jawnae.net.http.core.HttpResponse; import jawnae.net.http.core.HttpService; import jawnae.net.http.core.StatusCode; import jawnae.net.http.impl.HttpServerUtil; public class JavaFourKayShrinkService extends HttpService { static final String PATH_TO_JDK = "/root/jdk1.6.0_18/bin/"; static final String ALTERNATIVE_BOOTCLASSPATH = "/home/indiespot/java-15-rt.jar"; static final File GENERATED_FILE_BASE = new File("/home/indiespot/http-files/4k/"); static final long EXEC_DELAY = 250; static Lock queue_lock = new ReentrantLock(); @Override public void servePOST(HttpRequest request, HttpResponse response) throws Exception { try { if (request.isMultiPartPost()) { request.processMultiPartPost(); } String sourcecode = request.getCurrent("sourcecode"); boolean isJarOnly = sourcecode == null; boolean fixed = request.getCurrentBoolean("fixed"); int reruns = request.getCurrentBoolean("randomize") ? 8 : 1; int maxSplit = request.getCurrentBoolean("randomize") ? 256 : 4; response.setStatusCode(StatusCode.OK); response.setKeepAlive(false); response.setTransferEncodingChunked(true); response.setContentType("text/html"); String className; if (isJarOnly) { className = "x"; } else { className = Text.between(sourcecode, "public class", "{"); if (className == null) HttpServerUtil.abort(response, "public class name not found"); className = className.trim(); if (Text.indexOfWhiteSpace(className) != -1) className = className.substring(0, Text.indexOfWhiteSpace(className)); if (className.isEmpty()) HttpServerUtil.abort(response, "class name not found"); if (className.contains("..")) HttpServerUtil.abort(response, "class name invalid"); if (Text.before(sourcecode, "class").contains("package")) HttpServerUtil.abort(response, "class must not be in a package"); } PrintStream html = response.createPrintStream(); html.append(""); File javaFile = new File(GENERATED_FILE_BASE, className + ".java"); File classFile = new File(GENERATED_FILE_BASE, className + ".class"); if (sourcecode == null) sourcecode = Text.generateRandomCode(256); String downloadprefix = String.valueOf(Hash.toHex(Hash.md5(Text.utf8(sourcecode)))); if (className.equals("download")) throw new IllegalStateException(); int[] javaVersions = new int[] { /*5,*/6 }; String[] jarTypes = new String[] { "normal", "progrd" }; String[] compressors = new String[] { "7z", "kz", "bj" }; if (request.getCurrentBoolean("randomize")) { int delay = 90; for (int i = 0; i < delay; i++) { html.append(""); html.append("

added delay to discourage usage of the aggressive shrinker... " + (delay - i) + "sec

"); html.flush(); if (html.checkError()) return; Thread.sleep(1000); } } html.append("

waiting for work queue...

"); html.flush(); while (!queue_lock.tryLock()) { html.append(""); html.flush(); Thread.sleep(250); if (html.checkError()) return; } html.append(""); html.flush(); try { outer: if (true) { if (isJarOnly) { File tmp = request.getMultiPartFile("uploaded_jar"); FileUtil.copyFile(tmp, getTempResourceFilename(className, jarTypes[0], javaVersions[0], null, "jar")); } else { if (!source(html, sourcecode, javaFile)) break outer; if (html.checkError()) return; for (int javaVersion : javaVersions) { if (!javac(html, "javac (java" + javaVersion + ")", GENERATED_FILE_BASE, javaFile, javaVersion == 5 ? ALTERNATIVE_BOOTCLASSPATH : null)) break outer; if (html.checkError()) return; if (!jar(html, "jar (java" + javaVersion + ")", classFile, getTempResourceFilename(className, jarTypes[0], javaVersion, null, "jar"))) break outer; if (html.checkError()) return; } } for (int javaVersion : javaVersions) { File normalJar = getTempResourceFilename(className, jarTypes[0], javaVersion, null, "jar"); File progrdJar = getTempResourceFilename(className, jarTypes[1], javaVersion, null, "jar"); if (!proguard(html, "proguard (java" + javaVersion + ")", normalJar, progrdJar, fixed)) break outer; if (html.checkError()) return; } for (int javaVersion : javaVersions) { for (String jarType : jarTypes) { File xJarFile = getTempResourceFilename(className, jarType, javaVersion, null, "jar"); File xPackFile = getTempResourceFilename(className, jarType, javaVersion, null, "pack"); if (!pack200(html, "pack200 (java" + javaVersion + ")", xJarFile, xPackFile)) continue; for (String compressor : compressors) { File toDownload = getDownloadPackGzFilename(downloadprefix, jarType, javaVersion, compressor); boolean result; if (compressor.equals("7z")) result = gz_7z(html, "compress:7z (java" + javaVersion + ")", xPackFile, toDownload); else if (compressor.equals("kz")) result = bruteforceKzip(html, "compress:kzip (java" + javaVersion + ")", xPackFile, toDownload, 0, 4, 64, reruns) != -1; else if (compressor.equals("bj")) result = bruteforceBjwflate(html, "compress:bjwflate (java" + javaVersion + ")", xPackFile, toDownload, maxSplit) != -1; else throw new IllegalStateException("unexpected compressor: " + compressor); if (!result) toDownload.delete(); if (html.checkError()) return; } } } HighLevel.sleep(1000); html.append(""); html.flush(); html.append("

RESULT

");
               html.append(className + ".java => " + javaFile.length() + " bytes
"); html.append(className + ".class => " + classFile.length() + " bytes
"); for (int javaVersion : javaVersions) { for (String jarType : jarTypes) { File xJarFile = getTempResourceFilename(className, jarType, javaVersion, null, "jar"); File xPackFile = getTempResourceFilename(className, jarType, javaVersion, null, "pack"); html.append(xJarFile.getName() + " => " + xJarFile.length() + " bytes
"); html.append(xPackFile.getName() + " => " + xPackFile.length() + " bytes
"); } } class ResultEntry { File file; String html; } TreeSet entries = new TreeSet(new OrderComparator() { public boolean areEqual(ResultEntry a, ResultEntry b) { return false; } public boolean isOrdered(ResultEntry a, ResultEntry b) { return a.file.length() < b.file.length(); } }); for (int javaVersion : javaVersions) { for (String jarType : jarTypes) { for (String compressor : compressors) { File packGzFile = getDownloadPackGzFilename(downloadprefix, jarType, javaVersion, compressor); if (!packGzFile.exists()) continue; String htmlEntry = ""; htmlEntry += "" + Text.after(packGzFile.getName(), "download.") + " => " + packGzFile.length() + " bytes "; htmlEntry += " => test
"; ResultEntry entry = new ResultEntry(); entry.file = packGzFile; entry.html = htmlEntry; entries.add(entry); } } } for (ResultEntry entry : entries) { html.append(entry.html); } html.flush(); } } finally { queue_lock.unlock(); javaFile.delete(); classFile.delete(); for (int javaVersion : javaVersions) { for (String jarType : jarTypes) { File xJarFile = getTempResourceFilename(className, jarType, javaVersion, null, "jar"); File xPackFile = getTempResourceFilename(className, jarType, javaVersion, null, "pack"); xJarFile.delete(); xPackFile.delete(); } } html.close(); } } catch (Exception exc) { exc.printStackTrace(); } } private static File getTempResourceFilename(String className, String jarType, int javaVersion, String compressorIfAny, String extension) { String filename = className + "." + jarType + ".java" + javaVersion + (compressorIfAny == null ? "" : ("." + compressorIfAny)) + "." + extension; return new File(GENERATED_FILE_BASE, filename); } private static File getDownloadPackGzFilename(String downloadprefix, String jarType, int javaVersion, String compressor) { String filename = "download." + downloadprefix + "." + jarType + ".java" + javaVersion + "." + compressor + ".pack.gz"; return new File(GENERATED_FILE_BASE, filename); } private static boolean source(PrintStream html, String sourcecode, File javaFile) { System.out.println("create file"); try { FileUtil.writeFile(javaFile, Text.utf8(sourcecode)); html.append("

sourcecode

"); html.append("OK"); html.flush(); return true; } catch (Exception exc) { html.append("
");
         html.append("EXCEPTION: " + exc.getClass().getName() + "");
         html.append("
"); html.flush(); exc.printStackTrace(); return false; } } private static boolean javac(PrintStream html, String caption, File base, File javaFile, String alternativeBootClasspath) { System.out.println("javac"); try { List cmds = new ArrayList(); cmds.add(PATH_TO_JDK + "javac"); cmds.add("-nowarn"); cmds.add("-target"); cmds.add("1.5"); if (alternativeBootClasspath != null) { cmds.add("-bootclasspath"); cmds.add(alternativeBootClasspath); } cmds.add("-g:none"); cmds.add("-sourcepath"); cmds.add(base.getAbsolutePath()); cmds.add("-d"); cmds.add(base.getAbsolutePath()); cmds.add(javaFile.getAbsolutePath()); HighLevel.sleep(EXEC_DELAY); Process proc = Runtime.getRuntime().exec(cmds.toArray(new String[cmds.size()])); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); Streams.asynchronousTransfer(proc.getInputStream(), stdout); Streams.asynchronousTransfer(proc.getErrorStream(), stderr); int exit = proc.waitFor(); html.append("

" + caption + "

"); html.append("
");
         html.append("" + Text.utf8(stdout.toByteArray()) + "");
         html.append("
"); html.append("
");
         html.append("" + Text.utf8(stderr.toByteArray()) + "");
         html.append("
"); if (exit != 0) html.append("Exit value: " + exit + ""); else html.append("OK"); html.flush(); if (exit != 0) return false; return true; } catch (Exception exc) { html.append("
");
         html.append("EXCEPTION: " + exc.getClass().getName() + "");
         html.append("
"); html.flush(); exc.printStackTrace(); return false; } } private static boolean jar(PrintStream html, String caption, File classFile, File jarFile) { System.out.println("jar[" + classFile + "=>" + jarFile + "]"); try { html.append("

" + caption + "

"); html.append("OK"); List entries = new ArrayList(); entries.add(new ArchiveEntry(classFile, classFile.getName())); Compression.zip(entries, jarFile, true); html.flush(); return true; } catch (Exception exc) { html.append("
");
         html.append("EXCEPTION: " + exc.getClass().getName() + "");
         html.append("
"); html.flush(); exc.printStackTrace(); return false; } } private static boolean proguard(PrintStream html, String caption, File normalJarFile, File progrdJarFile, boolean fixed) { System.out.println("proguard"); try { String[] cmds = new String[9]; cmds[0] = PATH_TO_JDK + "java"; cmds[1] = "-jar"; cmds[2] = "/home/indiespot/proguard.jar"; cmds[3] = "-include"; cmds[4] = "/home/indiespot/" + (fixed ? "proguard.fixed.conf" : "proguard.conf"); cmds[5] = "-injars"; cmds[6] = normalJarFile.getAbsolutePath(); cmds[7] = "-outjars"; cmds[8] = progrdJarFile.getAbsolutePath(); HighLevel.sleep(EXEC_DELAY); Process proc = Runtime.getRuntime().exec(cmds); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); Streams.asynchronousTransfer(proc.getInputStream(), stdout); Streams.asynchronousTransfer(proc.getErrorStream(), stderr); int exit = proc.waitFor(); html.append("

" + caption + "

"); if (stderr.size() != 0) { html.append("
");
            html.append("" + Text.utf8(stdout.toByteArray()) + "");
            html.append("
"); html.append("
");
            html.append("" + Text.utf8(stderr.toByteArray()) + "");
            html.append("
"); } if (exit != 0) html.append("Exit value: " + exit + ""); else html.append("OK"); html.flush(); if (exit != 0) return false; return true; } catch (Exception exc) { html.append("
");
         html.append("EXCEPTION: " + exc.getClass().getName() + "");
         html.append("
"); html.flush(); exc.printStackTrace(); return false; } } private static boolean pack200(PrintStream html, String caption, File jarFile, File packFile) { System.out.println("pack200"); try { String[] cmds = new String[7]; cmds[0] = PATH_TO_JDK + "pack200"; cmds[1] = "--no-gzip"; cmds[2] = "--strip-debug"; cmds[3] = "--no-keep-file-order"; cmds[4] = "--effort=9"; cmds[5] = packFile.getAbsolutePath(); cmds[6] = jarFile.getAbsolutePath(); HighLevel.sleep(EXEC_DELAY); Process proc = Runtime.getRuntime().exec(cmds); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); Streams.asynchronousTransfer(proc.getInputStream(), stdout); Streams.asynchronousTransfer(proc.getErrorStream(), stderr); int exit = proc.waitFor(); html.append("

" + caption + "

"); if (stderr.size() != 0) { html.append("
");
            html.append("" + Text.utf8(stdout.toByteArray()) + "");
            html.append("
"); html.append("
");
            html.append("" + Text.utf8(stderr.toByteArray()) + "");
            html.append("
"); } if (exit != 0) html.append("Exit value: " + exit + ""); else html.append("OK:" + packFile.length() + ""); html.flush(); if (exit != 0) return false; return true; } catch (Exception exc) { html.append("
");
         html.append("EXCEPTION: " + exc.getClass().getName() + "");
         html.append("
"); html.flush(); exc.printStackTrace(); return false; } } private static int bruteforceKzip(PrintStream html, String caption, File packFile, File packGzFile, int splitOffset, int splitStep, int steps, int reruns) throws IOException { File min = packGzFile; File[] dst = new File[steps]; int minSplit = -1; for (int i = 0; i < dst.length; i++) { dst[i] = new File(packGzFile.getParentFile(), i + "_" + packGzFile.getName()); int split = splitOffset + i * splitStep; for (int k = 0; k < reruns; k++) { if (kzip_deflopt_gz(html, caption, packFile, dst[i], split, k != 0)) { if (dst[i].length() != 0 && ((min == null || min.length() == 0) || dst[i].length() < min.length())) { min = dst[i]; minSplit = split; } } } } if (minSplit != -1) FileUtil.copyFile(min, packGzFile); for (int i = 0; i < dst.length; i++) dst[i].delete(); return minSplit; } private static int bruteforceBjwflate(PrintStream html, String caption, File packFile, File packGzFile, int maxSplit) throws IOException { File min = packGzFile; int minSplit = -1; List dsts = new ArrayList(); for (int splitSize = 4, i = 0; splitSize <= maxSplit; splitSize += (splitSize <= 12 ? 4 : (splitSize <= 32 ? 8 : (splitSize <= 128 ? 16 : 32))), i++) { File dst = new File(packGzFile.getParentFile(), splitSize + "_" + packGzFile.getName()); if (bjwflate_deflopt_gz(html, caption, packFile, dst, splitSize, false)) { if (dst.length() != 0 && ((min == null || min.length() == 0) || dst.length() < min.length())) { min = dst; minSplit = splitSize; } } } if (minSplit != -1) FileUtil.copyFile(min, packGzFile); for (File dst : dsts) dst.delete(); return minSplit; } public static boolean kzip_deflopt_gz(PrintStream html, String caption, File src, File dst, int splitSize, boolean rn) { System.out.println("kzip:" + splitSize + " @ " + System.currentTimeMillis()); File zip = new File(src.getParentFile(), src.getName() + ".zip"); File dir = new File(src.getParentFile(), "tmp_" + System.nanoTime()); dir.mkdir(); try { // kzip try { FileUtil.copyFile(src, new File(dir, src.getName())); String[] cmds = new String[rn ? 5 : 4]; cmds[0] = "/root/kzipmix-static/kzip-static"; cmds[1] = "-y"; cmds[2] = "-b" + splitSize; if (rn) cmds[3] = "-rn"; cmds[rn ? 4 : 3] = zip.getAbsolutePath(); HighLevel.sleep(EXEC_DELAY); final Process proc = Runtime.getRuntime().exec(cmds, null, dir); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); Streams.asynchronousTransfer(proc.getInputStream(), stdout); Streams.asynchronousTransfer(proc.getErrorStream(), stderr); final SimpleCountDownLatch latch = new SimpleCountDownLatch(); new Thread() { public void run() { if (!latch.await(2 * 1000)) { proc.destroy(); } } }.start(); int exit = proc.waitFor(); latch.countDown(); if (splitSize == 0 && !rn) html.append("

" + caption + "

"); if (stderr.size() != 0) { html.append("
");
               html.append("" + Text.utf8(stdout.toByteArray()) + "");
               html.append("
"); html.append("
");
               html.append("" + Text.utf8(stderr.toByteArray()) + "");
               html.append("
"); } if (exit != 0) html.append("Exit value: " + exit + ""); html.flush(); if (exit != 0) return false; } catch (Exception exc) { html.append("
");
            html.append("EXCEPTION: " + exc.getClass().getName() + "");
            html.append("
"); html.flush(); exc.printStackTrace(); return false; } // gz try { zip2gz(new FileInputStream(zip), new FileOutputStream(dst)); html.append("OK "); html.flush(); } catch (IOException exc) { html.append("
");
            html.append("EXCEPTION: " + exc.getClass().getName() + "");
            html.append("
"); html.flush(); exc.printStackTrace(); return false; } return true; } finally { zip.delete(); FileUtil.deleteDirectory(dir, true); } } public static boolean bjwflate_deflopt_gz(PrintStream html, String caption, File src, File dst, int splitSize, boolean noprep) { System.out.println("bjwflate:" + splitSize + " @ " + System.currentTimeMillis()); File zip = new File(src.getParentFile(), src.getName() + ".zip"); try { // bjwflate try { String[] cmds = new String[noprep ? 6 : 5]; cmds[0] = "/usr/bin/wine"; cmds[1] = "/root/BJWFlate.exe"; cmds[2] = "-y"; if (noprep) cmds[3] = "-n"; cmds[noprep ? 4 : 3] = zip.getAbsolutePath(); cmds[noprep ? 5 : 4] = src.getAbsolutePath(); HighLevel.sleep(EXEC_DELAY); final Process proc = Runtime.getRuntime().exec(cmds, null); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); Streams.asynchronousTransfer(proc.getInputStream(), stdout); Streams.asynchronousTransfer(proc.getErrorStream(), stderr); final SimpleCountDownLatch latch = new SimpleCountDownLatch(); new Thread() { public void run() { if (!latch.await(2 * 1000)) { proc.destroy(); } } }.start(); int exit = proc.waitFor(); latch.countDown(); if (splitSize == 4) html.append("

" + caption + "

"); if (stderr.size() != 0) { html.append("
");
               html.append("" + Text.utf8(stdout.toByteArray()) + "");
               html.append("
"); html.append("
");
               html.append("" + Text.utf8(stderr.toByteArray()) + "");
               html.append("
"); } if (exit != 0) html.append("Exit value: " + exit + ""); html.flush(); if (exit != 0) return false; } catch (Exception exc) { html.append("
");
            html.append("EXCEPTION: " + exc.getClass().getName() + "");
            html.append("
"); html.flush(); exc.printStackTrace(); return false; } // deflopt { //deflopt(html, zip); } // gz try { zip2gz(new FileInputStream(zip), new FileOutputStream(dst)); html.append("OK "); html.flush(); } catch (IOException exc) { html.append("
");
            html.append("EXCEPTION: " + exc.getClass().getName() + "");
            html.append("
"); html.flush(); exc.printStackTrace(); return false; } return true; } finally { zip.delete(); } } public static boolean gz_7z(PrintStream html, String caption, File src, File dst) { System.out.println("7z"); try { String[] cmds = new String[4]; cmds[0] = "/root/p7zip_9.04/bin/7z"; cmds[1] = "a"; cmds[2] = dst.getAbsolutePath(); cmds[3] = src.getAbsolutePath(); HighLevel.sleep(EXEC_DELAY); Process proc = Runtime.getRuntime().exec(cmds); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); Streams.asynchronousTransfer(proc.getInputStream(), stdout); Streams.asynchronousTransfer(proc.getErrorStream(), stderr); int exit = proc.waitFor(); html.append("

" + caption + "

"); if (stderr.size() != 0) { html.append("
");
            html.append("" + Text.utf8(stdout.toByteArray()) + "");
            html.append("
"); html.append("
");
            html.append("" + Text.utf8(stderr.toByteArray()) + "");
            html.append("
"); } if (exit != 0) html.append("Exit value: " + exit + ""); else html.append("OK"); html.flush(); if (exit != 0) return false; return true; } catch (Exception exc) { html.append("
");
         html.append("EXCEPTION: " + exc.getClass().getName() + "");
         html.append("
"); html.flush(); exc.printStackTrace(); return false; } } public static void zip2gz(InputStream in, OutputStream out) throws IOException { in = new BufferedInputStream(in); out = new BufferedOutputStream(out); out.write(0x1f); out.write(0x8b); out.write(0x08); out.write(0x00); out.write(0x00); out.write(0x00); out.write(0x00); out.write(0x00); out.write(0x00); out.write(0xff); for (int i = 0; i < 14; i++) in.read(); int crc1 = in.read(); int crc2 = in.read(); int crc3 = in.read(); int crc4 = in.read(); int cmpSz = (in.read() & 0xff) + ((in.read() & 0xff) << 8) + ((in.read() & 0xff) << 16) + ((in.read() & 0xff) << 24); int ucmpSz1 = in.read(); int ucmpSz2 = in.read(); int ucmpSz3 = in.read(); int ucmpSz4 = in.read(); int nameLen = (in.read() & 0xff) + ((in.read() & 0xff) << 8); int xfLen = (in.read() & 0xff) + ((in.read() & 0xff) << 8); for (int i = 0; i < nameLen; i++) in.read(); for (int i = 0; i < xfLen; i++) in.read(); byte[] buf = new byte[4096]; while (cmpSz > 0) { int desired = cmpSz > buf.length ? buf.length : cmpSz; int len = in.read(buf, 0, desired); if (len == 0) throw new EOFException(); out.write(buf, 0, len); cmpSz -= len; } out.write(crc1); out.write(crc2); out.write(crc3); out.write(crc4); out.write(ucmpSz1); out.write(ucmpSz2); out.write(ucmpSz3); out.write(ucmpSz4); out.close(); in.close(); } }