PageRenderTime 39ms CodeModel.GetById 19ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/kilim/examples/HttpFileServer.java

http://github.com/kilim/kilim
Java | 299 lines | 249 code | 19 blank | 31 comment | 30 complexity | 3dfe0e692883c072edd4824af86099f7 MD5 | raw file
  1/* Copyright (c) 2006, Sriram Srinivasan
  2 *
  3 * You may distribute this software under the terms of the license 
  4 * specified in the file "License"
  5 */
  6
  7package kilim.examples;
  8
  9import java.io.EOFException;
 10import java.io.File;
 11import java.io.FileInputStream;
 12import java.io.IOException;
 13import java.io.PrintStream;
 14import java.nio.channels.FileChannel;
 15import java.util.HashMap;
 16
 17import kilim.Pausable;
 18import kilim.http.HttpRequest;
 19import kilim.http.HttpResponse;
 20import kilim.http.HttpServer;
 21import kilim.http.HttpSession;
 22
 23/**
 24 * A simple file server over http
 25 * 
 26 * Usage: Run java kilim.examples.HttpFileServer [base directory name] From a browser, go to "http://localhost:7262".
 27 * 
 28 * A HttpFileServer object is a SessionTask, and is thus a thin wrapper over the socket connection. Its execute() method
 29 * is called once on connection establishment. The HttpRequest and HttpResponse objects are wrappers over a bytebuffer,
 30 * and unrelated to the socket. The request object is "filled in" by HttpSession.readRequest() and the response object
 31 * is sent by HttpSession.sendResponse(). The rest of the code is related to the mechanics of file serving, common to
 32 * Kilim and non-Kilim approaches alike. The objective of this example is merely to demonstrate Kilim API, not to have a
 33 * fully functioning file server.
 34 */
 35public class HttpFileServer extends HttpSession {
 36    public static File   baseDirectory;
 37    public static String baseDirectoryName;
 38
 39    public static void main(String[] args) throws IOException {
 40        baseDirectoryName = ".";
 41        if (args.length > 0) {
 42            baseDirectoryName = args[0];
 43        }
 44        baseDirectory = new File(baseDirectoryName);
 45        if (!baseDirectory.isDirectory()) {
 46            usage();
 47        }
 48        baseDirectoryName = baseDirectory.getCanonicalPath();
 49
 50        // create a listener on port 7262. An instance of HttpFileServer is created upon
 51        // every new socket connection to this port.
 52        new HttpServer(7262, HttpFileServer.class);
 53        System.out.println("HttpFileServer listening on http://localhost:7262");
 54    }
 55
 56    public static void usage() {
 57        System.err.println("Usage: java kilim.examples.HttpFileServer [<baseDirectory>]");
 58        System.exit(1);
 59    }
 60
 61    @Override
 62    public void execute() throws Pausable, Exception {
 63        try {
 64            // We will reuse the req and resp objects
 65            HttpRequest req = new HttpRequest();
 66            HttpResponse resp = new HttpResponse();
 67            while (true) {
 68                // Fill up the request object. This pauses until the entire request has
 69                // been read in, including all chunks.
 70                super.readRequest(req);
 71                // System.out.println(req);
 72                if (req.method.equals("GET") || req.method.equals("HEAD")) {
 73                    File f = urlToPath(req);
 74                    System.out.println("[" + this.id + "] Read: " + f.getPath());
 75                    if (check(resp, f)) {
 76                        boolean headOnly = req.method.equals("HEAD");
 77                        if (f.isDirectory())
 78                            sendDirectory(resp, f, headOnly);
 79                        else
 80                            sendFile(resp, f, headOnly);
 81                    }
 82                } else {
 83                    super.problem(resp, HttpResponse.ST_FORBIDDEN, "Only GET and HEAD accepted");
 84                }
 85                if (!req.keepAlive()) {
 86                    break;
 87                }
 88            }
 89        } catch (EOFException e) {
 90            System.out.println("[" + this.id + "] Connection Terminated");
 91        } catch (IOException ioe) {
 92            System.out.println("[" + this.id + "] IO Exception:" + ioe.getMessage());
 93        }
 94        super.close();
 95    }
 96
 97    private File urlToPath(HttpRequest req) {
 98        return (req.uriPath == null) ? baseDirectory : new File(baseDirectory, req.uriPath);
 99    }
100
101    public boolean check(HttpResponse resp, File file) throws IOException, Pausable {
102        byte[] status = HttpResponse.ST_OK;
103        String msg = "";
104        
105        if (!file.exists()) {
106            status = HttpResponse.ST_NOT_FOUND;
107            msg = "File Not Found: " + file.getName();
108        } else if (!file.canRead()) {
109            status = HttpResponse.ST_FORBIDDEN;
110            msg = "Unable to read file " + file.getName();
111        } else {
112            try {
113                String path = file.getCanonicalPath();
114                if (!path.startsWith(baseDirectoryName)) {
115                    throw new SecurityException();
116                }
117            } catch (Exception e) {
118                status = HttpResponse.ST_FORBIDDEN;
119                msg = "Error retrieving " + file.getName() + ":<br>" + e.getMessage();
120            }
121        }
122        if (status != HttpResponse.ST_OK) {
123            problem(file, resp, status, msg);
124            return false;
125        } else {
126            return true;
127        }
128    }
129
130    public void sendFile(HttpResponse resp, File file, boolean headOnly) throws IOException, Pausable {
131        FileInputStream fis;
132        FileChannel fc;
133
134        try {
135            fis = new FileInputStream(file);
136            fc = fis.getChannel();
137        } catch (IOException ioe) {
138            problem(file, resp, HttpResponse.ST_NOT_FOUND, "Send exception: " + ioe.getMessage());
139            return;
140        }
141        try {
142            String contentType = mimeType(file);
143            if (contentType != null) {
144                resp.setContentType(contentType);
145            }
146            resp.setContentLength(file.length());
147            // Send the header first (with the content type and length)
148            super.sendResponse(resp);
149            // Send the contents; this uses sendfile or equivalent underneath.
150            endpoint.write(fc, 0, file.length());
151        } finally {
152            fc.close();
153            fis.close();
154        }
155    }
156
157    public void sendDirectory(HttpResponse resp, File file, boolean headOnly) throws Pausable, IOException {
158        PrintStream p = new PrintStream(resp.getOutputStream());
159        String relDir = getRelPath(file);
160        p.print("<html><head><title>Index of ");
161        p.print(relDir);
162        p.print("</title></head><body ");
163        p.print("><h2>Index of ");
164        p.print(relDir.equals(".") ? "/" : relDir);
165        p.print("</h2>");
166        String names[] = file.list();
167        if (names == null) {
168            p.print("No files found");
169        } else {
170            for (int i = 0; i < names.length; i++) {
171                // <a href="webpath">name</a>
172                p.print("<a href=\"");
173                p.print(relDir);
174                p.print('/');
175                p.print(names[i]);
176                p.print("\">");
177                p.print(names[i]);
178                p.print("</a><br>");
179            }
180        }
181        p.print("</body></html>");
182        p.flush();
183        super.sendResponse(resp);
184    }
185
186    public void problem(File file, HttpResponse resp, byte[] statusCode, String msg) throws IOException, Pausable {
187        System.out.println("[" + id + "]. Error retrieving " + file.getAbsolutePath() + "':\n   " + msg);
188        super.problem(resp, statusCode, msg);
189    }
190
191    private String getRelPath(File file) throws IOException {
192        String path = file.getCanonicalPath();
193        if (!path.startsWith(baseDirectoryName)) {
194            throw new SecurityException();
195        }
196        path =  path.substring(baseDirectoryName.length()); // include the "/"
197        return (path.length() == 0) ? "." : path;
198    }
199
200    public static HashMap<String, String> mimeTypes = new HashMap<String, String>();
201    
202    static {
203        mimeTypes.put("html", "text/html");
204        mimeTypes.put("htm", "text/html");
205        mimeTypes.put("txt", "text/plain");
206        mimeTypes.put("xml", "text/xml");
207        mimeTypes.put("css", "text/css");
208        mimeTypes.put("sgml", "text/x-sgml");
209        mimeTypes.put("sgm", "text/x-sgml");
210        // Images
211        mimeTypes.put("gif", "image/gif");
212        mimeTypes.put("jpg", "image/jpeg");
213        mimeTypes.put("jpeg", "image/jpeg");
214        mimeTypes.put("png", "image/png");
215        mimeTypes.put("bmp", "image/bmp");
216        mimeTypes.put("tif", "image/tiff");
217        mimeTypes.put("tiff", "image/tiff");
218        mimeTypes.put("rgb", "image/x-rgb");
219        mimeTypes.put("xpm", "image/x-xpixmap");
220        mimeTypes.put("xbm", "image/x-xbitmap");
221        mimeTypes.put("svg", "image/svg-xml ");
222        mimeTypes.put("svgz", "image/svg-xml ");
223        // Audio
224        mimeTypes.put("au", "audio/basic");
225        mimeTypes.put("snd", "audio/basic");
226        mimeTypes.put("mid", "audio/mid");
227        mimeTypes.put("midi", "audio/mid");
228        mimeTypes.put("rmi", "audio/mid");
229        mimeTypes.put("kar", "audio/mid");
230        mimeTypes.put("mpga", "audio/mpeg");
231        mimeTypes.put("mp2", "audio/mpeg");
232        mimeTypes.put("mp3", "audio/mpeg");
233        mimeTypes.put("wav", "audio/wav");
234        mimeTypes.put("aiff", "audio/aiff");
235        mimeTypes.put("aifc", "audio/aiff");
236        mimeTypes.put("aif", "audio/x-aiff");
237        mimeTypes.put("ra", "audio/x-realaudio");
238        mimeTypes.put("rpm", "audio/x-pn-realaudio-plugin");
239        mimeTypes.put("ram", "audio/x-pn-realaudio");
240        mimeTypes.put("sd2", "audio/x-sd2");
241        // Applications
242        mimeTypes.put("bin", "application/octet-stream");
243        mimeTypes.put("dms", "application/octet-stream");
244        mimeTypes.put("lha", "application/octet-stream");
245        mimeTypes.put("lzh", "application/octet-stream");
246        mimeTypes.put("exe", "application/octet-stream");
247        mimeTypes.put("dll", "application/octet-stream");
248        mimeTypes.put("class", "application/octet-stream");
249        mimeTypes.put("hqx", "application/mac-binhex40");
250        mimeTypes.put("ps", "application/postscript");
251        mimeTypes.put("eps", "application/postscript");
252        mimeTypes.put("pdf", "application/pdf");
253        mimeTypes.put("rtf", "application/rtf");
254        mimeTypes.put("doc", "application/msword");
255        mimeTypes.put("ppt", "application/powerpoint");
256        mimeTypes.put("fif", "application/fractals");
257        mimeTypes.put("p7c", "application/pkcs7-mime");
258        // Application/x
259        mimeTypes.put("js", "application/x-javascript");
260        mimeTypes.put("z", "application/x-compress");
261        mimeTypes.put("gz", "application/x-gzip");
262        mimeTypes.put("tar", "application/x-tar");
263        mimeTypes.put("tgz", "application/x-compressed");
264        mimeTypes.put("zip", "application/x-zip-compressed");
265        mimeTypes.put("dvi", "application/x-dvi");
266        mimeTypes.put("tex", "application/x-tex");
267        mimeTypes.put("latex", "application/x-latex");
268        mimeTypes.put("tcl", "application/x-tcl");
269        mimeTypes.put("cer", "application/x-x509-ca-cert");
270        mimeTypes.put("crt", "application/x-x509-ca-cert");
271        mimeTypes.put("der", "application/x-x509-ca-cert");
272        mimeTypes.put("iso", "application/x-iso9660-image");
273        // Video
274        mimeTypes.put("mpg", "video/mpeg");
275        mimeTypes.put("mpe", "video/mpeg");
276        mimeTypes.put("mpeg", "video/mpeg");
277        mimeTypes.put("qt", "video/quicktime");
278        mimeTypes.put("mov", "video/quicktime");
279        mimeTypes.put("avi", "video/x-msvideo");
280        mimeTypes.put("movie", "video/x-sgi-movie");
281        mimeTypes.put("jnlp", "application/x-java-jnlp-file");
282        mimeTypes.put("wrl", "x-world/x-vrml");
283        mimeTypes.put("vrml", "x-world/x-vrml");
284        mimeTypes.put("wml", "text/vnd.wap.wml");
285        mimeTypes.put("wmlc", "application/vnd.wap.wmlc");
286        mimeTypes.put("wmls", "text/vnd.wap.wmlscript");
287    }
288
289    public static String mimeType(File file) {
290        String name = file.getName();
291        int dotpos = name.lastIndexOf('.');
292        if (dotpos == -1)
293            return "text/plain";
294        else {
295            String mimeType = mimeTypes.get(name.substring(dotpos + 1).toLowerCase());
296            return (mimeType == null) ? "text/plain" : mimeType;
297        }
298    }
299}