KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > web > Webserver


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.web;
17
18 import java.net.*;
19 import java.io.*;
20 import java.util.Date JavaDoc;
21 import javassist.*;
22
23 /**
24  * A web server for Javassist.
25  *
26  * <p>This enables a Java program to instrument class files loaded by
27  * web browsers for applets. Since the (standard) security manager
28  * does not allow an applet to create and use a class loader,
29  * instrumenting class files must be done by this web server.
30  *
31  * <p><b>Note:</b> although this class is included in the Javassist API,
32  * it is provided as a sample implementation of the web server using
33  * Javassist. Especially, there might be security flaws in this server.
34  * Please use this with YOUR OWN RISK.
35  */

36 public class Webserver {
37     private ServerSocket socket;
38     private ClassPool classPool;
39     protected Translator translator;
40
41     private final static byte[] endofline = { 0x0d, 0x0a };
42     private byte[] filebuffer = new byte[4096];
43
44     private final static int typeHtml = 1;
45     private final static int typeClass = 2;
46     private final static int typeGif = 3;
47     private final static int typeJpeg = 4;
48     private final static int typeText = 5;
49     private final static int typeUnknown = 6;
50
51     /**
52      * If this field is not null, the class files taken from
53      * <code>ClassPool</code> are written out under the directory
54      * specified by this field. The directory name must not end
55      * with a directory separator.
56      */

57     public String JavaDoc debugDir = null;
58
59     /**
60      * The top directory of html (and .gif, .class, ...) files.
61      * It must end with the directory separator such as "/".
62      * (For portability, "/" should be used as the directory separator.
63      * Javassist automatically translates "/" into a platform-dependent
64      * character.)
65      * If this field is null, the top directory is the current one where
66      * the JVM is running.
67      *
68      * <p>If the given URL indicates a class file and the class file
69      * is not found under the directory specified by this variable,
70      * then <code>Class.getResourceAsStream()</code> is called
71      * for searching the Java class paths.
72      */

73     public String JavaDoc htmlfileBase = null;
74
75     /**
76      * Starts a web server.
77      * The port number is specified by the first argument.
78      */

79     public static void main(String JavaDoc[] args) throws IOException {
80         if (args.length == 1) {
81             Webserver web = new Webserver(args[0]);
82             web.run();
83         }
84         else
85             System.err.println(
86                         "Usage: java javassist.web.Webserver <port number>");
87     }
88
89     /**
90      * Constructs a web server.
91      *
92      * @param port port number
93      */

94     public Webserver(String JavaDoc port) throws IOException {
95         this(Integer.parseInt(port));
96     }
97
98     /**
99      * Constructs a web server.
100      *
101      * @param port port number
102      */

103     public Webserver(int port) throws IOException {
104         socket = new ServerSocket(port);
105         classPool = null;
106         translator = null;
107     }
108
109     /**
110      * Requests the web server to use the specified
111      * <code>ClassPool</code> object for obtaining a class file.
112      */

113     public void setClassPool(ClassPool loader) {
114         classPool = loader;
115     }
116
117     /**
118      * Adds a translator, which is called whenever a client requests
119      * a class file.
120      *
121      * @param cp the <code>ClassPool</code> object for obtaining
122      * a class file.
123      * @param t a translator.
124      */

125     public void addTranslator(ClassPool cp, Translator t)
126         throws NotFoundException, CannotCompileException
127     {
128         classPool = cp;
129         translator = t;
130         t.start(classPool);
131     }
132
133     /**
134      * Closes the socket.
135      */

136     public void end() throws IOException {
137         socket.close();
138     }
139
140     /**
141      * Prints a log message.
142      */

143     public void logging(String JavaDoc msg) {
144         System.out.println(msg);
145     }
146
147     /**
148      * Prints a log message.
149      */

150     public void logging(String JavaDoc msg1, String JavaDoc msg2) {
151         System.out.print(msg1);
152         System.out.print(" ");
153         System.out.println(msg2);
154     }
155
156     /**
157      * Prints a log message.
158      */

159     public void logging(String JavaDoc msg1, String JavaDoc msg2, String JavaDoc msg3) {
160         System.out.print(msg1);
161         System.out.print(" ");
162         System.out.print(msg2);
163         System.out.print(" ");
164         System.out.println(msg3);
165     }
166
167     /**
168      * Prints a log message with indentation.
169      */

170     public void logging2(String JavaDoc msg) {
171         System.out.print(" ");
172         System.out.println(msg);
173     }
174
175     /**
176      * Begins the HTTP service.
177      */

178     public void run() {
179         System.err.println("ready to service...");
180         for (;;)
181             try {
182                 ServiceThread th = new ServiceThread(this, socket.accept());
183                 th.start();
184             }
185             catch (IOException e) {
186                 logging(e.toString());
187             }
188     }
189
190     final void process(Socket clnt) throws IOException {
191         InputStream in = new BufferedInputStream(clnt.getInputStream());
192         String JavaDoc cmd = readLine(in);
193         logging(clnt.getInetAddress().getHostName(),
194                 new Date JavaDoc().toString(), cmd);
195         while (skipLine(in) > 0){
196         }
197
198         OutputStream out = new BufferedOutputStream(clnt.getOutputStream());
199         try {
200             doReply(in, out, cmd);
201         }
202         catch (BadHttpRequest e) {
203             replyError(out, e);
204         }
205
206         out.flush();
207         in.close();
208         out.close();
209         clnt.close();
210     }
211
212     private String JavaDoc readLine(InputStream in) throws IOException {
213         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
214         int c;
215         while ((c = in.read()) >= 0 && c != 0x0d)
216             buf.append((char)c);
217
218         in.read(); /* skip 0x0a (LF) */
219         return buf.toString();
220     }
221
222     private int skipLine(InputStream in) throws IOException {
223         int c;
224         int len = 0;
225         while ((c = in.read()) >= 0 && c != 0x0d)
226             ++len;
227
228         in.read(); /* skip 0x0a (LF) */
229         return len;
230     }
231
232     /**
233      * Proceses a HTTP request from a client.
234      *
235      * @param out the output stream to a client
236      * @param cmd the command received from a client
237      */

238     public void doReply(InputStream in, OutputStream out, String JavaDoc cmd)
239         throws IOException, BadHttpRequest
240     {
241         int len;
242         int fileType;
243         String JavaDoc filename, urlName;
244
245         if (cmd.startsWith("GET /"))
246             filename = urlName = cmd.substring(5, cmd.indexOf(' ', 5));
247         else
248             throw new BadHttpRequest();
249
250         if (filename.endsWith(".class"))
251             fileType = typeClass;
252         else if (filename.endsWith(".html") || filename.endsWith(".htm"))
253             fileType = typeHtml;
254         else if (filename.endsWith(".gif"))
255             fileType = typeGif;
256         else if (filename.endsWith(".jpg"))
257             fileType = typeJpeg;
258         else
259             fileType = typeText; // or textUnknown
260

261         len = filename.length();
262         if (fileType == typeClass
263             && letUsersSendClassfile(out, filename, len))
264             return;
265
266         checkFilename(filename, len);
267         if (htmlfileBase != null)
268             filename = htmlfileBase + filename;
269
270         if (File.separatorChar != '/')
271             filename = filename.replace('/', File.separatorChar);
272
273         File file = new File(filename);
274         if (file.canRead()) {
275             sendHeader(out, file.length(), fileType);
276             FileInputStream fin = new FileInputStream(file);
277             for (;;) {
278                 len = fin.read(filebuffer);
279                 if (len <= 0)
280                     break;
281                 else
282                     out.write(filebuffer, 0, len);
283             }
284
285             fin.close();
286             return;
287         }
288
289         // If the file is not found under the html-file directory,
290
// then Class.getResourceAsStream() is tried.
291

292         if (fileType == typeClass) {
293             InputStream fin
294                 = getClass().getResourceAsStream("/" + urlName);
295             if (fin != null) {
296                 ByteArrayOutputStream barray = new ByteArrayOutputStream();
297                 for (;;) {
298                     len = fin.read(filebuffer);
299                     if (len <= 0)
300                         break;
301                     else
302                         barray.write(filebuffer, 0, len);
303                 }
304
305                 byte[] classfile = barray.toByteArray();
306                 sendHeader(out, classfile.length, typeClass);
307                 out.write(classfile);
308                 fin.close();
309                 return;
310             }
311         }
312
313         throw new BadHttpRequest();
314     }
315
316     private void checkFilename(String JavaDoc filename, int len)
317         throws BadHttpRequest
318     {
319         for (int i = 0; i < len; ++i) {
320             char c = filename.charAt(i);
321             if (!Character.isJavaIdentifierPart(c) && c != '.' && c != '/')
322                 throw new BadHttpRequest();
323         }
324
325         if (filename.indexOf("..") >= 0)
326             throw new BadHttpRequest();
327     }
328
329     private boolean letUsersSendClassfile(OutputStream out,
330                                           String JavaDoc filename, int length)
331         throws IOException, BadHttpRequest
332     {
333         if (classPool == null)
334             return false;
335
336         byte[] classfile;
337         String JavaDoc classname
338             = filename.substring(0, length - 6).replace('/', '.');
339         try {
340             if (translator != null)
341                 translator.onLoad(classPool, classname);
342
343             CtClass c = classPool.get(classname);
344             classfile = c.toBytecode();
345             if (debugDir != null)
346                 c.writeFile(debugDir);
347         }
348         catch (Exception JavaDoc e) {
349             throw new BadHttpRequest(e);
350         }
351
352         sendHeader(out, classfile.length, typeClass);
353         out.write(classfile);
354         return true;
355     }
356
357     private void sendHeader(OutputStream out, long dataLength, int filetype)
358         throws IOException
359     {
360         out.write("HTTP/1.0 200 OK".getBytes());
361         out.write(endofline);
362         out.write("Content-Length: ".getBytes());
363         out.write(Long.toString(dataLength).getBytes());
364         out.write(endofline);
365         if (filetype == typeClass)
366             out.write("Content-Type: application/octet-stream".getBytes());
367         else if (filetype == typeHtml)
368             out.write("Content-Type: text/html".getBytes());
369         else if (filetype == typeGif)
370             out.write("Content-Type: image/gif".getBytes());
371         else if (filetype == typeJpeg)
372             out.write("Content-Type: image/jpg".getBytes());
373         else if (filetype == typeText)
374             out.write("Content-Type: text/plain".getBytes());
375
376         out.write(endofline);
377         out.write(endofline);
378     }
379
380     private void replyError(OutputStream out, BadHttpRequest e)
381         throws IOException
382     {
383         logging2("bad request: " + e.toString());
384         out.write("HTTP/1.0 400 Bad Request".getBytes());
385         out.write(endofline);
386         out.write(endofline);
387         out.write("<H1>Bad Request</H1>".getBytes());
388     }
389 }
390
391 class ServiceThread extends Thread JavaDoc {
392     Webserver web;
393     Socket sock;
394
395     public ServiceThread(Webserver w, Socket s) {
396         web = w;
397         sock = s;
398     }
399
400     public void run() {
401         try {
402             web.process(sock);
403         }
404         catch (IOException e) {
405         }
406     }
407 }
408
Popular Tags