Added a general-purpose root error handler.
authorFredrik Tolf <fredrik@dolda2000.com>
Mon, 12 Oct 2009 22:01:59 +0000 (00:01 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Mon, 12 Oct 2009 22:01:59 +0000 (00:01 +0200)
src/dolda/jsvc/test/Bootstrap.java
src/dolda/jsvc/test/TestResponder.java
src/dolda/jsvc/util/ErrorHandler.java [new file with mode: 0644]

index 49abdd2..bb72f30 100644 (file)
@@ -1,9 +1,10 @@
 package dolda.jsvc.test;
 
 import dolda.jsvc.*;
+import dolda.jsvc.util.*;
 
 public class Bootstrap {
     public static Responder responder() {
-       return(new TestResponder());
+       return(new ErrorHandler(new TestResponder()));
     }
 }
index d7541b4..414dfef 100644 (file)
@@ -13,6 +13,9 @@ public class TestResponder implements Responder {
            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>");
@@ -23,6 +26,9 @@ public class TestResponder implements Responder {
        out.println(req.remoteaddr() + "<->" + req.localaddr());
        out.println("</body>");
        out.println("</html>");
+
+       if(req.path().equals("bard2"))
+           throw(new RuntimeException("bard2"));
        out.flush();
     }
 }
diff --git a/src/dolda/jsvc/util/ErrorHandler.java b/src/dolda/jsvc/util/ErrorHandler.java
new file mode 100644 (file)
index 0000000..f1149e8
--- /dev/null
@@ -0,0 +1,79 @@
+package dolda.jsvc.util;
+
+import dolda.jsvc.*;
+import java.net.*;
+import java.io.*;
+import java.util.logging.*;
+
+public class ErrorHandler implements Responder {
+    private Responder next;
+    private static Logger logger = Logger.getLogger("jsvc.error");
+    
+    public ErrorHandler(Responder next) {
+       this.next = next;
+    }
+    
+    protected void log(Request req, Throwable t) {
+       logger.log(Level.SEVERE, "Unhandled error in responder", t);
+    }
+    
+    protected void respdebug(Request req, Throwable t) {
+       req.status(500);
+       req.outheaders().put("content-type", "text/plain; charset=utf-8");
+       PrintWriter out;
+       try {
+           out = new PrintWriter(new OutputStreamWriter(req.output(), "UTF-8"));
+       } catch(UnsupportedEncodingException e) {
+           throw(new Error(e));
+       }
+       t.printStackTrace(out);
+       out.flush();
+    }
+    
+    protected void resperr(Request req, Throwable t) {
+       req.status(500);
+       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>Internal error</title></head>");
+       out.println("<body>");
+       out.println("<h1>Internal error</h1>");
+       out.println("An error occurred on the server processing your request.");
+       out.println("</body>");
+       out.println("</html>");
+       out.flush();
+    }
+    
+    protected boolean debug(Request req, Throwable t) {
+       SocketAddress rem = req.remoteaddr();
+       return((rem instanceof InetSocketAddress) && ((InetSocketAddress)rem).getAddress().isLoopbackAddress());
+    }
+
+    protected void handle(Request req, Throwable t) {
+       log(req, t);
+       if(req instanceof ResettableRequest) {
+           ResettableRequest rr = (ResettableRequest)req;
+           if(rr.canreset())
+               rr.reset();
+       }
+       if(debug(req, t))
+           respdebug(req, t);
+       else
+           resperr(req, t);
+    }
+    
+    public void respond(Request req) {
+       try {
+           next.respond(req);
+       } catch(Throwable t) {
+           handle(req, t);
+       }
+    }
+}