169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.tools.web;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.net.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.*;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Date;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.*;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A web server for running sample programs.
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>This enables a Java program to instrument class files loaded by
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * web browsers for applets.  Since the (standard) security manager
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * does not allow an applet to create and use a class loader,
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instrumenting class files must be done by this web server.
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p><b>Note:</b> although this class is included in the Javassist API,
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * it is provided as a sample implementation of the web server using
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist.  Especially, there might be security flaws in this server.
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Please use this with YOUR OWN RISK.
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Webserver {
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ServerSocket socket;
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ClassPool classPool;
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected Translator translator;
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final static byte[] endofline = { 0x0d, 0x0a };
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final static int typeHtml = 1;
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final static int typeClass = 2;
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final static int typeGif = 3;
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final static int typeJpeg = 4;
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final static int typeText = 5;
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If this field is not null, the class files taken from
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>ClassPool</code> are written out under the directory
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * specified by this field.  The directory name must not end
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * with a directory separator.
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String debugDir = null;
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The top directory of html (and .gif, .class, ...) files.
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It must end with the directory separator such as "/".
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * (For portability, "/" should be used as the directory separator.
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Javassist automatically translates "/" into a platform-dependent
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * character.)
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If this field is null, the top directory is the current one where
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the JVM is running.
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>If the given URL indicates a class file and the class file
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * is not found under the directory specified by this variable,
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * then <code>Class.getResourceAsStream()</code> is called
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * for searching the Java class paths.
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String htmlfileBase = null;
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Starts a web server.
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The port number is specified by the first argument.
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static void main(String[] args) throws IOException {
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (args.length == 1) {
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Webserver web = new Webserver(args[0]);
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            web.run();
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            System.err.println(
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        "Usage: java javassist.tools.web.Webserver <port number>");
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a web server.
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port      port number
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Webserver(String port) throws IOException {
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(Integer.parseInt(port));
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a web server.
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port      port number
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Webserver(int port) throws IOException {
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        socket = new ServerSocket(port);
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classPool = null;
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        translator = null;
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Requests the web server to use the specified
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>ClassPool</code> object for obtaining a class file.
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setClassPool(ClassPool loader) {
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classPool = loader;
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Adds a translator, which is called whenever a client requests
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * a class file.
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param cp        the <code>ClassPool</code> object for obtaining
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  a class file.
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param t         a translator.
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void addTranslator(ClassPool cp, Translator t)
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws NotFoundException, CannotCompileException
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classPool = cp;
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        translator = t;
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        t.start(classPool);
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Closes the socket.
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void end() throws IOException {
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        socket.close();
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints a log message.
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void logging(String msg) {
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.println(msg);
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints a log message.
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void logging(String msg1, String msg2) {
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print(msg1);
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print(" ");
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.println(msg2);
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints a log message.
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void logging(String msg1, String msg2, String msg3) {
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print(msg1);
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print(" ");
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print(msg2);
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print(" ");
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.println(msg3);
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints a log message with indentation.
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void logging2(String msg) {
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.print("    ");
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.out.println(msg);
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Begins the HTTP service.
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void run() {
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        System.err.println("ready to service...");
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (;;)
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ServiceThread th = new ServiceThread(this, socket.accept());
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                th.start();
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (IOException e) {
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                logging(e.toString());
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    final void process(Socket clnt) throws IOException {
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        InputStream in = new BufferedInputStream(clnt.getInputStream());
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String cmd = readLine(in);
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        logging(clnt.getInetAddress().getHostName(),
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                new Date().toString(), cmd);
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (skipLine(in) > 0){
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        OutputStream out = new BufferedOutputStream(clnt.getOutputStream());
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            doReply(in, out, cmd);
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (BadHttpRequest e) {
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            replyError(out, e);
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.flush();
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        in.close();
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.close();
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clnt.close();
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String readLine(InputStream in) throws IOException {
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        StringBuffer buf = new StringBuffer();
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int c;
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while ((c = in.read()) >= 0 && c != 0x0d)
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            buf.append((char)c);
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        in.read();      /* skip 0x0a (LF) */
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return buf.toString();
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private int skipLine(InputStream in) throws IOException {
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int c;
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int len = 0;
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while ((c = in.read()) >= 0 && c != 0x0d)
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ++len;
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        in.read();      /* skip 0x0a (LF) */
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return len;
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Proceses a HTTP request from a client.
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param out       the output stream to a client
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param cmd       the command received from a client
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void doReply(InputStream in, OutputStream out, String cmd)
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, BadHttpRequest
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int len;
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int fileType;
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String filename, urlName;
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (cmd.startsWith("GET /"))
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            filename = urlName = cmd.substring(5, cmd.indexOf(' ', 5));
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new BadHttpRequest();
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (filename.endsWith(".class"))
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            fileType = typeClass;
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filename.endsWith(".html") || filename.endsWith(".htm"))
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            fileType = typeHtml;
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filename.endsWith(".gif"))
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            fileType = typeGif;
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filename.endsWith(".jpg"))
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            fileType = typeJpeg;
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            fileType = typeText;        // or textUnknown
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        len = filename.length();
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (fileType == typeClass
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            && letUsersSendClassfile(out, filename, len))
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return;
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        checkFilename(filename, len);
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (htmlfileBase != null)
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            filename = htmlfileBase + filename;
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (File.separatorChar != '/')
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            filename = filename.replace('/', File.separatorChar);
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        File file = new File(filename);
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (file.canRead()) {
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sendHeader(out, file.length(), fileType);
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            FileInputStream fin = new FileInputStream(file);
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            byte[] filebuffer = new byte[4096];
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            for (;;) {
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                len = fin.read(filebuffer);
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (len <= 0)
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    break;
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                else
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    out.write(filebuffer, 0, len);
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            fin.close();
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return;
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // If the file is not found under the html-file directory,
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // then Class.getResourceAsStream() is tried.
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (fileType == typeClass) {
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            InputStream fin
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                = getClass().getResourceAsStream("/" + urlName);
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (fin != null) {
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ByteArrayOutputStream barray = new ByteArrayOutputStream();
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                byte[] filebuffer = new byte[4096];
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                for (;;) {
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    len = fin.read(filebuffer);
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (len <= 0)
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        break;
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    else
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        barray.write(filebuffer, 0, len);
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                byte[] classfile = barray.toByteArray();
30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                sendHeader(out, classfile.length, typeClass);
30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                out.write(classfile);
30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                fin.close();
30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return;
31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new BadHttpRequest();
31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void checkFilename(String filename, int len)
31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws BadHttpRequest
31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < len; ++i) {
32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            char c = filename.charAt(i);
32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (!Character.isJavaIdentifierPart(c) && c != '.' && c != '/')
32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new BadHttpRequest();
32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (filename.indexOf("..") >= 0)
32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new BadHttpRequest();
32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean letUsersSendClassfile(OutputStream out,
33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          String filename, int length)
33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, BadHttpRequest
33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (classPool == null)
33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;
33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        byte[] classfile;
33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String classname
33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            = filename.substring(0, length - 6).replace('/', '.');
33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (translator != null)
34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                translator.onLoad(classPool, classname);
34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtClass c = classPool.get(classname);
34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            classfile = c.toBytecode();
34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (debugDir != null)
34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                c.writeFile(debugDir);
34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (Exception e) {
34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new BadHttpRequest(e);
35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        sendHeader(out, classfile.length, typeClass);
35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(classfile);
35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return true;
35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void sendHeader(OutputStream out, long dataLength, int filetype)
35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException
35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write("HTTP/1.0 200 OK".getBytes());
36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(endofline);
36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write("Content-Length: ".getBytes());
36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(Long.toString(dataLength).getBytes());
36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(endofline);
36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (filetype == typeClass)
36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write("Content-Type: application/octet-stream".getBytes());
36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filetype == typeHtml)
36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write("Content-Type: text/html".getBytes());
36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filetype == typeGif)
37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write("Content-Type: image/gif".getBytes());
37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filetype == typeJpeg)
37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write("Content-Type: image/jpg".getBytes());
37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (filetype == typeText)
37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write("Content-Type: text/plain".getBytes());
37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(endofline);
37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(endofline);
37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void replyError(OutputStream out, BadHttpRequest e)
38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException
38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        logging2("bad request: " + e.toString());
38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write("HTTP/1.0 400 Bad Request".getBytes());
38569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(endofline);
38669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write(endofline);
38769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.write("<H1>Bad Request</H1>".getBytes());
38869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
38969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
39069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
39169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalclass ServiceThread extends Thread {
39269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    Webserver web;
39369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    Socket sock;
39469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
39569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ServiceThread(Webserver w, Socket s) {
39669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        web = w;
39769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        sock = s;
39869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
39969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
40069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void run() {
40169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
40269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            web.process(sock);
40369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
40469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (IOException e) {
40569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
40669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
40769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
408