123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.web;
-
- import java.net.*;
- import java.io.*;
- import java.util.Date;
- import javassist.*;
-
- /**
- * A web server for running sample programs.
- *
- * <p>This enables a Java program to instrument class files loaded by
- * web browsers for applets. Since the (standard) security manager
- * does not allow an applet to create and use a class loader,
- * instrumenting class files must be done by this web server.
- *
- * <p><b>Note:</b> although this class is included in the Javassist API,
- * it is provided as a sample implementation of the web server using
- * Javassist. Especially, there might be security flaws in this server.
- * Please use this with YOUR OWN RISK.
- */
- public class Webserver {
- private ServerSocket socket;
- private ClassPool classPool;
- protected Translator translator;
-
- private final static byte[] endofline = { 0x0d, 0x0a };
- private byte[] filebuffer = new byte[4096];
-
- private final static int typeHtml = 1;
- private final static int typeClass = 2;
- private final static int typeGif = 3;
- private final static int typeJpeg = 4;
- private final static int typeText = 5;
-
- /**
- * If this field is not null, the class files taken from
- * <code>ClassPool</code> are written out under the directory
- * specified by this field. The directory name must not end
- * with a directory separator.
- */
- public String debugDir = null;
-
- /**
- * The top directory of html (and .gif, .class, ...) files.
- * It must end with the directory separator such as "/".
- * (For portability, "/" should be used as the directory separator.
- * Javassist automatically translates "/" into a platform-dependent
- * character.)
- * If this field is null, the top directory is the current one where
- * the JVM is running.
- *
- * <p>If the given URL indicates a class file and the class file
- * is not found under the directory specified by this variable,
- * then <code>Class.getResourceAsStream()</code> is called
- * for searching the Java class paths.
- */
- public String htmlfileBase = null;
-
- /**
- * Starts a web server.
- * The port number is specified by the first argument.
- */
- public static void main(String[] args) throws IOException {
- if (args.length == 1) {
- Webserver web = new Webserver(args[0]);
- web.run();
- }
- else
- System.err.println(
- "Usage: java javassist.web.Webserver <port number>");
- }
-
- /**
- * Constructs a web server.
- *
- * @param port port number
- */
- public Webserver(String port) throws IOException {
- this(Integer.parseInt(port));
- }
-
- /**
- * Constructs a web server.
- *
- * @param port port number
- */
- public Webserver(int port) throws IOException {
- socket = new ServerSocket(port);
- classPool = null;
- translator = null;
- }
-
- /**
- * Requests the web server to use the specified
- * <code>ClassPool</code> object for obtaining a class file.
- */
- public void setClassPool(ClassPool loader) {
- classPool = loader;
- }
-
- /**
- * Adds a translator, which is called whenever a client requests
- * a class file.
- *
- * @param cp the <code>ClassPool</code> object for obtaining
- * a class file.
- * @param t a translator.
- */
- public void addTranslator(ClassPool cp, Translator t)
- throws NotFoundException, CannotCompileException
- {
- classPool = cp;
- translator = t;
- t.start(classPool);
- }
-
- /**
- * Closes the socket.
- */
- public void end() throws IOException {
- socket.close();
- }
-
- /**
- * Prints a log message.
- */
- public void logging(String msg) {
- System.out.println(msg);
- }
-
- /**
- * Prints a log message.
- */
- public void logging(String msg1, String msg2) {
- System.out.print(msg1);
- System.out.print(" ");
- System.out.println(msg2);
- }
-
- /**
- * Prints a log message.
- */
- public void logging(String msg1, String msg2, String msg3) {
- System.out.print(msg1);
- System.out.print(" ");
- System.out.print(msg2);
- System.out.print(" ");
- System.out.println(msg3);
- }
-
- /**
- * Prints a log message with indentation.
- */
- public void logging2(String msg) {
- System.out.print(" ");
- System.out.println(msg);
- }
-
- /**
- * Begins the HTTP service.
- */
- public void run() {
- System.err.println("ready to service...");
- for (;;)
- try {
- ServiceThread th = new ServiceThread(this, socket.accept());
- th.start();
- }
- catch (IOException e) {
- logging(e.toString());
- }
- }
-
- final void process(Socket clnt) throws IOException {
- InputStream in = new BufferedInputStream(clnt.getInputStream());
- String cmd = readLine(in);
- logging(clnt.getInetAddress().getHostName(),
- new Date().toString(), cmd);
- while (skipLine(in) > 0){
- }
-
- OutputStream out = new BufferedOutputStream(clnt.getOutputStream());
- try {
- doReply(in, out, cmd);
- }
- catch (BadHttpRequest e) {
- replyError(out, e);
- }
-
- out.flush();
- in.close();
- out.close();
- clnt.close();
- }
-
- private String readLine(InputStream in) throws IOException {
- StringBuffer buf = new StringBuffer();
- int c;
- while ((c = in.read()) >= 0 && c != 0x0d)
- buf.append((char)c);
-
- in.read(); /* skip 0x0a (LF) */
- return buf.toString();
- }
-
- private int skipLine(InputStream in) throws IOException {
- int c;
- int len = 0;
- while ((c = in.read()) >= 0 && c != 0x0d)
- ++len;
-
- in.read(); /* skip 0x0a (LF) */
- return len;
- }
-
- /**
- * Proceses a HTTP request from a client.
- *
- * @param out the output stream to a client
- * @param cmd the command received from a client
- */
- public void doReply(InputStream in, OutputStream out, String cmd)
- throws IOException, BadHttpRequest
- {
- int len;
- int fileType;
- String filename, urlName;
-
- if (cmd.startsWith("GET /"))
- filename = urlName = cmd.substring(5, cmd.indexOf(' ', 5));
- else
- throw new BadHttpRequest();
-
- if (filename.endsWith(".class"))
- fileType = typeClass;
- else if (filename.endsWith(".html") || filename.endsWith(".htm"))
- fileType = typeHtml;
- else if (filename.endsWith(".gif"))
- fileType = typeGif;
- else if (filename.endsWith(".jpg"))
- fileType = typeJpeg;
- else
- fileType = typeText; // or textUnknown
-
- len = filename.length();
- if (fileType == typeClass
- && letUsersSendClassfile(out, filename, len))
- return;
-
- checkFilename(filename, len);
- if (htmlfileBase != null)
- filename = htmlfileBase + filename;
-
- if (File.separatorChar != '/')
- filename = filename.replace('/', File.separatorChar);
-
- File file = new File(filename);
- if (file.canRead()) {
- sendHeader(out, file.length(), fileType);
- FileInputStream fin = new FileInputStream(file);
- for (;;) {
- len = fin.read(filebuffer);
- if (len <= 0)
- break;
- else
- out.write(filebuffer, 0, len);
- }
-
- fin.close();
- return;
- }
-
- // If the file is not found under the html-file directory,
- // then Class.getResourceAsStream() is tried.
-
- if (fileType == typeClass) {
- InputStream fin
- = getClass().getResourceAsStream("/" + urlName);
- if (fin != null) {
- ByteArrayOutputStream barray = new ByteArrayOutputStream();
- for (;;) {
- len = fin.read(filebuffer);
- if (len <= 0)
- break;
- else
- barray.write(filebuffer, 0, len);
- }
-
- byte[] classfile = barray.toByteArray();
- sendHeader(out, classfile.length, typeClass);
- out.write(classfile);
- fin.close();
- return;
- }
- }
-
- throw new BadHttpRequest();
- }
-
- private void checkFilename(String filename, int len)
- throws BadHttpRequest
- {
- for (int i = 0; i < len; ++i) {
- char c = filename.charAt(i);
- if (!Character.isJavaIdentifierPart(c) && c != '.' && c != '/')
- throw new BadHttpRequest();
- }
-
- if (filename.indexOf("..") >= 0)
- throw new BadHttpRequest();
- }
-
- private boolean letUsersSendClassfile(OutputStream out,
- String filename, int length)
- throws IOException, BadHttpRequest
- {
- if (classPool == null)
- return false;
-
- byte[] classfile;
- String classname
- = filename.substring(0, length - 6).replace('/', '.');
- try {
- if (translator != null)
- translator.onLoad(classPool, classname);
-
- CtClass c = classPool.get(classname);
- classfile = c.toBytecode();
- if (debugDir != null)
- c.writeFile(debugDir);
- }
- catch (Exception e) {
- throw new BadHttpRequest(e);
- }
-
- sendHeader(out, classfile.length, typeClass);
- out.write(classfile);
- return true;
- }
-
- private void sendHeader(OutputStream out, long dataLength, int filetype)
- throws IOException
- {
- out.write("HTTP/1.0 200 OK".getBytes());
- out.write(endofline);
- out.write("Content-Length: ".getBytes());
- out.write(Long.toString(dataLength).getBytes());
- out.write(endofline);
- if (filetype == typeClass)
- out.write("Content-Type: application/octet-stream".getBytes());
- else if (filetype == typeHtml)
- out.write("Content-Type: text/html".getBytes());
- else if (filetype == typeGif)
- out.write("Content-Type: image/gif".getBytes());
- else if (filetype == typeJpeg)
- out.write("Content-Type: image/jpg".getBytes());
- else if (filetype == typeText)
- out.write("Content-Type: text/plain".getBytes());
-
- out.write(endofline);
- out.write(endofline);
- }
-
- private void replyError(OutputStream out, BadHttpRequest e)
- throws IOException
- {
- logging2("bad request: " + e.toString());
- out.write("HTTP/1.0 400 Bad Request".getBytes());
- out.write(endofline);
- out.write(endofline);
- out.write("<H1>Bad Request</H1>".getBytes());
- }
- }
-
- class ServiceThread extends Thread {
- Webserver web;
- Socket sock;
-
- public ServiceThread(Webserver w, Socket s) {
- web = w;
- sock = s;
- }
-
- public void run() {
- try {
- web.process(sock);
- }
- catch (IOException e) {
- }
- }
- }
|