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