Added initial SCGI server and a handler for serving JARs from the filesystem.
[jsvc.git] / src / dolda / jsvc / scgi / Server.java
CommitLineData
13e578b1
FT
1package dolda.jsvc.scgi;
2
3import java.util.logging.*;
4import java.io.*;
5import java.net.*;
6import java.util.*;
7
8public abstract class Server implements Runnable {
9 private final ServerSocket sk;
10 private final Logger logger = Logger.getLogger("dolda.jsvc.scgi");
11 public String headcs = "UTF-8";
12
13 public Server(ServerSocket sk) {
14 this.sk = sk;
15 }
16
17 private static int readnslen(InputStream in) throws IOException {
18 int ret = 0;
19 while(true) {
20 int c = in.read();
21 if(c == ':')
22 return(ret);
23 else if((c >= '0') && (c <= '9'))
24 ret = (ret * 10) + (c - '0');
25 else
26 throw(new InvalidRequestException("Malformed netstring length"));
27 }
28 }
29
30 private static byte[] readns(InputStream in) throws IOException {
31 byte[] buf = new byte[readnslen(in)];
32 int off = 0;
33 while(off < buf.length) {
34 int ret = in.read(buf, off, buf.length - off);
35 if(ret < 0)
36 throw(new InvalidRequestException("Unexpected EOS in netstring"));
37 off += ret;
38 }
39 if(in.read() != ',')
40 throw(new InvalidRequestException("Unterminated netstring"));
41 return(buf);
42 }
43
44 private Map<String, String> readhead(InputStream in) throws IOException {
45 byte[] rawhead = readns(in);
46 String head = new String(rawhead, headcs);
47 Map<String, String> ret = new HashMap<String, String>();
48 int p = 0;
49 while(true) {
50 int p2 = head.indexOf(0, p);
51 if(p2 < 0) {
52 if(p == head.length())
53 return(ret);
54 throw(new InvalidRequestException("Malformed headers"));
55 }
56 String key = head.substring(p, p2);
57 int p3 = head.indexOf(0, p2 + 1);
58 if(p3 < 0)
59 throw(new InvalidRequestException("Malformed headers"));
60 String val = head.substring(p2 + 1, p3);
61 ret.put(key, val);
62 p = p3 + 1;
63 }
64 }
65
66 private boolean checkhead(Map<String, String> head) {
67 if(!head.containsKey("SCGI") || !head.get("SCGI").equals("1"))
68 return(false);
69 return(true);
70 }
71
72 protected abstract void handle(Map<String, String> head, Socket sk) throws Exception;
73
74 private void serve(Socket sk) {
75 try {
76 try {
77 InputStream in = sk.getInputStream();
78 Map<String, String> head = readhead(in);
79 if(!checkhead(head))
80 return;
81 try {
82 handle(head, sk);
83 } catch(Exception e) {
84 logger.log(Level.WARNING, "Could not handle request", e);
85 return;
86 }
87 sk = null;
88 } finally {
89 if(sk != null)
90 sk.close();
91 }
92 } catch(IOException e) {
93 logger.log(Level.WARNING, "I/O error encountered while serving SCGI request", e);
94 }
95 }
96
97 public void run() {
98 try {
99 try {
100 while(true) {
101 Socket nsk = sk.accept();
102 serve(nsk);
103 }
104 } finally {
105 sk.close();
106 }
107 } catch(IOException e) {
108 logger.log(Level.SEVERE, "SCGI server encountered I/O error", e);
109 }
110 }
111}