kilim.examples.HttpFileServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kilim Show documentation
Show all versions of kilim Show documentation
Coroutines, continuations, fibers, actors and message passing for the JVM
The newest version!
/* Copyright (c) 2006, Sriram Srinivasan
*
* You may distribute this software under the terms of the license
* specified in the file "License"
*/
package kilim.examples;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import kilim.Pausable;
import kilim.http.HttpRequest;
import kilim.http.HttpResponse;
import kilim.http.HttpServer;
import kilim.http.HttpSession;
import kilim.http.MimeTypes;
/**
* A simple file server over http
*
* Usage: Run java kilim.examples.HttpFileServer [base directory name] From a browser, go to "http://localhost:7262".
*
* A HttpFileServer object is a SessionTask, and is thus a thin wrapper over the socket connection. Its execute() method
* is called once on connection establishment. The HttpRequest and HttpResponse objects are wrappers over a bytebuffer,
* and unrelated to the socket. The request object is "filled in" by HttpSession.readRequest() and the response object
* is sent by HttpSession.sendResponse(). The rest of the code is related to the mechanics of file serving, common to
* Kilim and non-Kilim approaches alike. The objective of this example is merely to demonstrate Kilim API, not to have a
* fully functioning file server.
*/
public class HttpFileServer extends HttpSession {
public static File baseDirectory;
public static String baseDirectoryName;
public static void main(String[] args) throws IOException {
baseDirectoryName = ".";
if (args.length > 0) {
baseDirectoryName = args[0];
}
baseDirectory = new File(baseDirectoryName);
if (!baseDirectory.isDirectory()) {
usage();
}
baseDirectoryName = baseDirectory.getCanonicalPath();
// create a listener on port 7262. An instance of HttpFileServer is created upon
// every new socket connection to this port.
new HttpServer(7262, HttpFileServer.class);
System.out.println("HttpFileServer listening on http://localhost:7262");
}
public static void usage() {
System.err.println("Usage: java kilim.examples.HttpFileServer []");
System.exit(1);
}
@Override
public void execute() throws Pausable, Exception {
try {
// We will reuse the req and resp objects
HttpRequest req = new HttpRequest();
HttpResponse resp = new HttpResponse();
while (true) {
// Fill up the request object. This pauses until the entire request has
// been read in, including all chunks.
super.readRequest(req);
// System.out.println(req);
if (req.method.equals("GET") || req.method.equals("HEAD")) {
File f = urlToPath(req);
System.out.println("[" + this.id + "] Read: " + f.getPath());
if (check(resp, f)) {
boolean headOnly = req.method.equals("HEAD");
if (f.isDirectory())
sendDirectory(resp, f, headOnly);
else
sendFile(resp, f, headOnly);
}
} else {
super.problem(resp, HttpResponse.ST_FORBIDDEN, "Only GET and HEAD accepted");
}
if (!req.keepAlive()) {
break;
}
}
} catch (EOFException e) {
System.out.println("[" + this.id + "] Connection Terminated");
} catch (IOException ioe) {
System.out.println("[" + this.id + "] IO Exception:" + ioe.getMessage());
}
super.close();
}
private File urlToPath(HttpRequest req) {
return (req.uriPath == null) ? baseDirectory : new File(baseDirectory, req.uriPath);
}
public boolean check(HttpResponse resp, File file) throws IOException, Pausable {
byte[] status = HttpResponse.ST_OK;
String msg = "";
if (!file.exists()) {
status = HttpResponse.ST_NOT_FOUND;
msg = "File Not Found: " + file.getName();
} else if (!file.canRead()) {
status = HttpResponse.ST_FORBIDDEN;
msg = "Unable to read file " + file.getName();
} else {
try {
String path = file.getCanonicalPath();
if (!path.startsWith(baseDirectoryName)) {
throw new SecurityException();
}
} catch (Exception e) {
status = HttpResponse.ST_FORBIDDEN;
msg = "Error retrieving " + file.getName() + ":
" + e.getMessage();
}
}
if (status != HttpResponse.ST_OK) {
problem(file, resp, status, msg);
return false;
} else {
return true;
}
}
public void sendFile(HttpResponse resp, File file, boolean headOnly) throws IOException, Pausable {
FileInputStream fis;
FileChannel fc;
try {
fis = new FileInputStream(file);
fc = fis.getChannel();
} catch (IOException ioe) {
problem(file, resp, HttpResponse.ST_NOT_FOUND, "Send exception: " + ioe.getMessage());
return;
}
try {
String contentType = MimeTypes.mimeType(file);
if (contentType != null) {
resp.setContentType(contentType);
}
resp.setContentLength(file.length());
// Send the header first (with the content type and length)
super.sendResponse(resp);
// Send the contents; this uses sendfile or equivalent underneath.
endpoint.write(fc, 0, file.length());
} finally {
fc.close();
fis.close();
}
}
public void sendDirectory(HttpResponse resp, File file, boolean headOnly) throws Pausable, IOException {
PrintStream p = new PrintStream(resp.getOutputStream());
String relDir = getRelPath(file);
p.print("Index of ");
p.print(relDir);
p.print(" Index of ");
p.print(relDir.equals(".") ? "/" : relDir);
p.print("
");
String names[] = file.list();
if (names == null) {
p.print("No files found");
} else {
for (int i = 0; i < names.length; i++) {
// name
p.print("");
p.print(names[i]);
p.print("
");
}
}
p.print("");
p.flush();
super.sendResponse(resp);
}
public void problem(File file, HttpResponse resp, byte[] statusCode, String msg) throws IOException, Pausable {
System.out.println("[" + id + "]. Error retrieving " + file.getAbsolutePath() + "':\n " + msg);
super.problem(resp, statusCode, msg);
}
private String getRelPath(File file) throws IOException {
String path = file.getCanonicalPath();
if (!path.startsWith(baseDirectoryName)) {
throw new SecurityException();
}
path = path.substring(baseDirectoryName.length()); // include the "/"
return (path.length() == 0) ? "." : path;
}
public static HashMap mimeTypes = new HashMap();
static {
mimeTypes.put("html", "text/html");
mimeTypes.put("htm", "text/html");
mimeTypes.put("txt", "text/plain");
mimeTypes.put("xml", "text/xml");
mimeTypes.put("css", "text/css");
mimeTypes.put("sgml", "text/x-sgml");
mimeTypes.put("sgm", "text/x-sgml");
// Images
mimeTypes.put("gif", "image/gif");
mimeTypes.put("jpg", "image/jpeg");
mimeTypes.put("jpeg", "image/jpeg");
mimeTypes.put("png", "image/png");
mimeTypes.put("bmp", "image/bmp");
mimeTypes.put("tif", "image/tiff");
mimeTypes.put("tiff", "image/tiff");
mimeTypes.put("rgb", "image/x-rgb");
mimeTypes.put("xpm", "image/x-xpixmap");
mimeTypes.put("xbm", "image/x-xbitmap");
mimeTypes.put("svg", "image/svg+xml ");
mimeTypes.put("svgz", "image/svg+xml ");
// Audio
mimeTypes.put("au", "audio/basic");
mimeTypes.put("snd", "audio/basic");
mimeTypes.put("mid", "audio/mid");
mimeTypes.put("midi", "audio/mid");
mimeTypes.put("rmi", "audio/mid");
mimeTypes.put("kar", "audio/mid");
mimeTypes.put("mpga", "audio/mpeg");
mimeTypes.put("mp2", "audio/mpeg");
mimeTypes.put("mp3", "audio/mpeg");
mimeTypes.put("wav", "audio/wav");
mimeTypes.put("aiff", "audio/aiff");
mimeTypes.put("aifc", "audio/aiff");
mimeTypes.put("aif", "audio/x-aiff");
mimeTypes.put("ra", "audio/x-realaudio");
mimeTypes.put("rpm", "audio/x-pn-realaudio-plugin");
mimeTypes.put("ram", "audio/x-pn-realaudio");
mimeTypes.put("sd2", "audio/x-sd2");
// Applications
mimeTypes.put("bin", "application/octet-stream");
mimeTypes.put("dms", "application/octet-stream");
mimeTypes.put("lha", "application/octet-stream");
mimeTypes.put("lzh", "application/octet-stream");
mimeTypes.put("exe", "application/octet-stream");
mimeTypes.put("dll", "application/octet-stream");
mimeTypes.put("class", "application/octet-stream");
mimeTypes.put("hqx", "application/mac-binhex40");
mimeTypes.put("ps", "application/postscript");
mimeTypes.put("eps", "application/postscript");
mimeTypes.put("pdf", "application/pdf");
mimeTypes.put("rtf", "application/rtf");
mimeTypes.put("doc", "application/msword");
mimeTypes.put("ppt", "application/powerpoint");
mimeTypes.put("fif", "application/fractals");
mimeTypes.put("p7c", "application/pkcs7-mime");
// Application/x
mimeTypes.put("js", "application/x-javascript");
mimeTypes.put("z", "application/x-compress");
mimeTypes.put("gz", "application/x-gzip");
mimeTypes.put("tar", "application/x-tar");
mimeTypes.put("tgz", "application/x-compressed");
mimeTypes.put("zip", "application/x-zip-compressed");
mimeTypes.put("dvi", "application/x-dvi");
mimeTypes.put("tex", "application/x-tex");
mimeTypes.put("latex", "application/x-latex");
mimeTypes.put("tcl", "application/x-tcl");
mimeTypes.put("cer", "application/x-x509-ca-cert");
mimeTypes.put("crt", "application/x-x509-ca-cert");
mimeTypes.put("der", "application/x-x509-ca-cert");
mimeTypes.put("iso", "application/x-iso9660-image");
// Video
mimeTypes.put("mpg", "video/mpeg");
mimeTypes.put("mpe", "video/mpeg");
mimeTypes.put("mpeg", "video/mpeg");
mimeTypes.put("qt", "video/quicktime");
mimeTypes.put("mov", "video/quicktime");
mimeTypes.put("avi", "video/x-msvideo");
mimeTypes.put("movie", "video/x-sgi-movie");
mimeTypes.put("jnlp", "application/x-java-jnlp-file");
mimeTypes.put("wrl", "x-world/x-vrml");
mimeTypes.put("vrml", "x-world/x-vrml");
mimeTypes.put("wml", "text/vnd.wap.wml");
mimeTypes.put("wmlc", "application/vnd.wap.wmlc");
mimeTypes.put("wmls", "text/vnd.wap.wmlscript");
}
public static String mimeType(File file) {
String name = file.getName();
int dotpos = name.lastIndexOf('.');
if (dotpos == -1)
return "text/plain";
else {
String mimeType = mimeTypes.get(name.substring(dotpos + 1).toLowerCase());
return (mimeType == null) ? "text/plain" : mimeType;
}
}
}