Added initial SCGI server and a handler for serving JARs from the filesystem.
[jsvc.git] / src / dolda / jsvc / scgi / DirServer.java
1 package dolda.jsvc.scgi;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.*;
6 import dolda.jsvc.*;
7 import dolda.jsvc.util.*;
8 import dolda.jsvc.j2ee.PosixArgs;
9
10 public class DirServer extends Server {
11     private final Map<File, DSContext> contexts = new HashMap<File, DSContext>();
12     private final File datroot;
13     
14     public DirServer(ServerSocket sk, File datroot) {
15         super(sk);
16         this.datroot = datroot;
17     }
18
19     private DSContext context(File file) throws ThreadContext.CreateException {
20         synchronized(contexts) {
21             DSContext ctx = contexts.get(file);
22             if(ctx != null) {
23                 if(ctx.mtime < file.lastModified()) {
24                     ctx.tg.destroy();
25                     contexts.remove(file);
26                     ctx = null;
27                 }
28             }
29             if(ctx == null) {
30                 ctx = new DSContext(file, datroot);
31                 contexts.put(file, ctx);
32             }
33             return(ctx);
34         }
35     }
36
37     public void handle(Map<String, String> head, Socket sk) throws Exception {
38         String filename = head.get("SCRIPT_FILENAME");
39         if(filename == null)
40             throw(new Exception("Request for DirServer must contain SCRIPT_FILENAME"));
41         File file = new File(filename);
42         if(!file.exists() || !file.canRead())
43             throw(new Exception("Cannot access the requested JSvc file " + file.toString()));
44         DSContext ctx = context(file);
45         Request req = new ScgiRequest(sk, head);
46         RequestThread w = ctx.tg.respond(req);
47         w.start();
48     }
49
50     private static void usage(PrintStream out) {
51         out.println("usage: dolda.jsvc.scgi.DirServer [-h] [-e CHARSET] [-d DATADIR] PORT");
52     }
53     
54     public static void main(String[] args) {
55         PosixArgs opt = PosixArgs.getopt(args, "h");
56         if(opt == null) {
57             usage(System.err);
58             System.exit(1);
59         }
60         String charset = null;
61         File datroot = null;
62         for(char c : opt.parsed()) {
63             switch(c) {
64             case 'e':
65                 charset = opt.arg;
66                 break;
67             case 'd':
68                 datroot = new File(opt.arg);
69                 if(!datroot.exists() || !datroot.isDirectory()) {
70                     System.err.println(opt.arg + ": no such directory");
71                     System.exit(1);
72                 }
73                 break;
74             case 'h':
75                 usage(System.out);
76                 return;
77             }
78         }
79         if(opt.rest.length < 1) {
80             usage(System.err);
81             System.exit(1);
82         }
83         if(datroot == null) {
84             datroot = new File(System.getProperty("user.home"), ".jsvc");
85             if(!datroot.exists() || !datroot.isDirectory())
86                 datroot = null;
87         }
88         int port = Integer.parseInt(opt.rest[0]);
89         ServerSocket sk;
90         try {
91             sk = new ServerSocket(port);
92         } catch(IOException e) {
93             System.err.println("could not bind to port " + port + ": " + e.getMessage());
94             System.exit(1);
95             return; /* Because javac is stupid. :-/ */
96         }
97         DirServer s = new DirServer(sk, datroot);
98         if(charset != null)
99             s.headcs = charset;
100         
101         new Thread(s, "SCGI server thread").start();
102     }
103 }