<target name="test-war" depends="build-env, jsvc-jar">
<taskdef name="jsvc-war" classname="dolda.jsvc.j2ee.Archive$AntTask" classpath="build/jsvc.jar" />
+ <copy todir="build/test-bin/dolda/jsvc/test">
+ <fileset dir="src/dolda/jsvc/test">
+ <include name="static/**" />
+ </fileset>
+ </copy>
<copy tofile="build/test-bin/jsvc.properties" file="etc/test.jsvc.properties" />
<jar destfile="build/jsvc-test.jar" basedir="build/test-bin" />
<jsvc-war destfile="build/jsvc-test.war">
package dolda.jsvc.j2ee;
+import dolda.jsvc.util.*;
import java.util.*;
import java.io.*;
import java.net.*;
return(props);
}
- private static void cpstream(InputStream in, OutputStream out) throws IOException {
- byte[] buf = new byte[4096];
- while(true) {
- int ret = in.read(buf, 0, buf.length);
- if(ret < 0)
- return;
- out.write(buf, 0, ret);
- }
- }
-
private static class MissingPropException extends RuntimeException {
public final String prop;
public void addcode(String name, InputStream in) throws IOException {
zip().putNextEntry(new ZipEntry("WEB-INF/classes/" + name));
- cpstream(in, zip());
+ Misc.cpstream(in, zip());
}
public void addjars(File[] jars) throws IOException {
zip.putNextEntry(new ZipEntry("WEB-INF/lib/" + jar.getName()));
InputStream jarin = new FileInputStream(jar);
try {
- cpstream(jarin, zip);
+ Misc.cpstream(jarin, zip);
} finally {
jarin.close();
}
public class Bootstrap {
public static Responder responder() {
- return(new ErrorHandler(new Rehandler(new TestResponder())));
+ Multiplexer root = new Multiplexer();
+ root.file("test", new TestResponder());
+ root.file("", new StaticContent(Bootstrap.class, "static/index.html", false, "text/html"));
+ root.file("css", new StaticContent(Bootstrap.class, "static/test.css", false, "text/css"));
+ root.dir("foo", new StaticContent(Bootstrap.class, "static/foo", true, "text/plain; charset=utf-8"));
+ return(Misc.stdroot(root));
}
}
import dolda.jsvc.util.*;
import java.io.*;
-public class TestResponder implements Responder {
- public void respond(Request req) {
- req.outheaders().put("Content-Type", "text/html; charset=utf-8");
- PrintWriter out;
- try {
- out = new PrintWriter(new OutputStreamWriter(req.output(), "UTF-8"));
- } catch(UnsupportedEncodingException e) {
- throw(new Error(e));
- }
-
- if(req.path().equals("bard1"))
- throw(new RuntimeException("bard1"));
-
- out.println("<html>");
- out.println("<head><title>Barda</title></head>");
- out.println("<body>");
- out.println("<h1>Barda</h1>");
- out.println("Bardslen.");
+public class TestResponder extends SimpleWriter {
+ public TestResponder() {
+ super("plain");
+ }
+
+ public void respond(Request req, PrintWriter out) {
+ out.println(req.url());
+ out.println(req.path());
out.println(req.inheaders());
out.println(req.ctx().starttime());
out.println(req.remoteaddr() + "<->" + req.localaddr());
- out.println("</body>");
- out.println("</html>");
-
- if(req.path().equals("bard2"))
- throw(Restarts.redirectctx("/slen"));
- out.flush();
}
}
--- /dev/null
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+<head>
+<title>Test</title>
+<link rel="stylesheet" title="Default style" type="text/css" href="css" />
+</head>
+<body>
+<h1>Hello world!</h1>
+<p>Test</p>
+</body>
+</html>
--- /dev/null
+body {
+ font-family: sans;
+}
--- /dev/null
+package dolda.jsvc.util;
+
+import java.util.*;
+import java.text.*;
+
+public class Http {
+ public final static DateFormat datefmt;
+ static {
+ datefmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
+ datefmt.setCalendar(Calendar.getInstance(TimeZone.getTimeZone("UTC")));
+ }
+
+ public static String fmtdate(Date d) {
+ return(datefmt.format(d));
+ }
+
+ public static Date parsedate(String str) throws ParseException {
+ return(datefmt.parse(str));
+ }
+}
package dolda.jsvc.util;
+import dolda.jsvc.*;
import java.util.*;
+import java.io.*;
public class Misc {
private static Map<Integer, String> stext = new HashMap<Integer, String>();
stext.put(301, "Permanently Moved");
stext.put(302, "Temporarily Moved");
stext.put(303, "See Other");
+ stext.put(304, "Not Modified");
stext.put(400, "Bad Request");
stext.put(401, "Authentication Required");
stext.put(403, "Access Forbidden");
p = p.substring(1);
return(p);
}
+
+ public static void cpstream(InputStream in, OutputStream out) throws IOException {
+ byte[] buf = new byte[4096];
+ while(true) {
+ int ret = in.read(buf, 0, buf.length);
+ if(ret < 0)
+ return;
+ out.write(buf, 0, ret);
+ }
+ }
+
+ public static Responder stdroot(Responder root) {
+ Responder ret = root;
+ ret = new Rehandler(ret);
+ ret = new ErrorHandler(ret);
+ return(ret);
+ }
}
}
public Multiplexer() {
- this(new SimpleWriter("html") {
- public void respond(Request req, java.io.PrintWriter out) {
- req.status(404);
- out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">");
- out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en-US\">");
- out.println("<head><title>Resource not found</title></head>");
- out.println("<body>");
- out.println("<h1>Resource not found</h1>");
- out.println("The resource you requested could not be found on this server.");
- out.println("</body>");
- out.println("</html>");
+ this(new Responder() {
+ public void respond(Request req) {
+ throw(Restarts.stdresponse(404, "Resource not found", "The resource you requested could not be found on this server."));
}
});
}
import dolda.jsvc.*;
import java.net.*;
+import java.io.*;
public class Restarts {
public static RequestRestart redirect(final URL to) {
}
});
}
+
+ public static RequestRestart stdresponse(final int code, final String title, final String message) {
+ return(new RequestRestart() {
+ public void respond(Request req) {
+ req.status(code);
+ req.outheaders().put("content-type", "text/html; charset=us-ascii");
+ PrintWriter out;
+ try {
+ out = new PrintWriter(new OutputStreamWriter(req.output(), "US-ASCII"));
+ } catch(UnsupportedEncodingException e) {
+ throw(new Error(e));
+ }
+ out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">");
+ out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en-US\">");
+ out.println("<head><title>" + title + "</title></head>");
+ out.println("<body>");
+ out.println("<h1>" + title + "</h1>");
+ out.println(message);
+ out.println("</body>");
+ out.println("</html>");
+ out.flush();
+ }
+ });
+ }
+
+ public static RequestRestart stdresponse(int code, String message) {
+ return(stdresponse(code, "An error occurred", message));
+ }
+
+ public static RequestRestart stdresponse(int code) {
+ return(stdresponse(code, "An error occurred", Misc.statustext(code)));
+ }
}
--- /dev/null
+package dolda.jsvc.util;
+
+import dolda.jsvc.*;
+import java.io.*;
+import java.util.*;
+
+public class StaticContent implements Responder {
+ private final Class<?> base;
+ private final String resname;
+ private final boolean dir;
+ private final String mimetype;
+
+ public StaticContent(Class<?> base, String resname, boolean dir, String mimetype) {
+ this.base = base;
+ this.resname = resname;
+ this.dir = dir;
+ this.mimetype = mimetype;
+ }
+
+ public StaticContent(String resname, boolean dir, String mimetype) {
+ this(null, resname, dir, mimetype);
+ }
+
+ public void respond(Request req) {
+ String nm;
+ if(dir) {
+ nm = resname + "/" + req.path();
+ } else {
+ nm = resname;
+ }
+ InputStream in;
+ if(base == null) {
+ in = StaticContent.class.getClassLoader().getResourceAsStream(nm);
+ } else {
+ in = base.getResourceAsStream(nm);
+ }
+ if(in == null)
+ throw(Restarts.stdresponse(404));
+ String ims = req.inheaders().get("If-Modified-Since");
+ Date mtime = new Date((req.ctx().starttime() / 1000) * 1000);
+ if(ims != null) {
+ Date d;
+ try {
+ d = Http.parsedate(ims);
+ } catch(java.text.ParseException e) {
+ throw(Restarts.stdresponse(400));
+ }
+ if(mtime.compareTo(d) <= 0) {
+ req.status(304);
+ req.outheaders().put("Content-Length", "0");
+ return;
+ }
+ }
+ try {
+ try {
+ req.outheaders().put("Content-Type", mimetype);
+ req.outheaders().put("Last-Modified", Http.fmtdate(mtime));
+ Misc.cpstream(in, req.output());
+ } finally {
+ in.close();
+ }
+ } catch(IOException e) {
+ throw(new Error(e));
+ }
+ }
+}