1 package dolda.jsvc.scgi;
7 import dolda.jsvc.util.*;
9 public class ScgiRequest extends ResponseBuffer {
11 private final Map<String, String> environ;
12 private final InputStream in;
13 private final String method, path;
14 private final URL url, context;
15 private MultiMap<String, String> params = null;
16 private MultiMap<String, String> inhead = new HeaderTreeMap();
18 public ScgiRequest(Socket sk, Map<String, String> environ) throws IOException {
20 this.environ = environ;
21 for(Map.Entry<String, String> var : environ.entrySet()) {
22 String k = var.getKey();
23 if((k.length() > 5) && k.substring(0, 5).equals("HTTP_")) {
24 StringBuilder buf = new StringBuilder();
26 for(int i = 5; i < k.length(); i++) {
32 buf.append(Character.toUpperCase(c));
35 buf.append(Character.toLowerCase(c));
38 inhead.add(buf.toString(), var.getValue());
43 String h = environ.get("CONTENT_LENGTH");
48 len = Long.parseLong(h);
49 } catch(NumberFormatException e) {
50 throw(new InvalidRequestException("Invalid Content-Length header: " + h));
54 this.in = new LimitInputStream(sk.getInputStream(), len);
55 path = environ.get("PATH_INFO");
57 throw(new InvalidRequestException("Missing PATH_INFO"));
59 String tmp = environ.get("REQUEST_METHOD");
61 throw(new InvalidRequestException("Missing REQUEST_METHOD"));
62 method = tmp.toUpperCase().intern();
65 /* Ewwww, this is disgusting! */
66 String scheme = "http";
67 if(environ.get("HTTPS") != null)
70 String host = environ.get("HTTP_HOST");
71 if((host == null) || (host.length() < 1)) {
72 if((host = environ.get("SERVER_NAME")) == null)
73 throw(new InvalidRequestException("Both HTTP_HOST and SERVER name are missing"));
74 String portnum = environ.get("SERVER_PORT");
76 throw(new InvalidRequestException("Missing SERVER_PORT"));
78 port = Integer.parseInt(portnum);
79 } catch(NumberFormatException e) {
80 throw(new InvalidRequestException("Bad SERVER_PORT: " + portnum));
82 if((port == 80) && scheme.equals("http"))
84 else if((port == 443) && scheme.equals("https"))
88 if((host.charAt(0) == '[') && ((p = host.indexOf(']', 1)) > 1)) {
89 String newhost = host.substring(1, p);
90 if((p = host.indexOf(':', p + 1)) >= 0) {
92 port = Integer.parseInt(host.substring(p + 1));
93 } catch(NumberFormatException e) {}
96 } else if((p = host.indexOf(':')) >= 0) {
98 port = Integer.parseInt(host.substring(p + 1));
99 host = host.substring(0, p);
100 } catch(NumberFormatException e) {}
103 String nm = environ.get("SCRIPT_NAME");
105 throw(new InvalidRequestException("Missing SCRIPT_NAME"));
106 String q = environ.get("QUERY_STRING");
112 url = new URL(scheme, host, port, nm + path + q);
113 if(nm.charAt(nm.length() - 1) != '/')
114 nm += "/"; /* XXX? */
115 context = new URL(scheme, host, port, nm);
116 } catch(MalformedURLException e) {
122 public MultiMap<String, String> inheaders() {
126 public ServerContext ctx() {
127 return(ThreadContext.current().server());
130 public InputStream input() {
138 public URL rooturl() {
142 public String path() {
146 public String method() {
150 public MultiMap<String, String> params() {
152 params = Params.stdparams(this);
156 public SocketAddress localaddr() {
157 String portnum = environ.get("SERVER_PORT");
161 port = Integer.parseInt(portnum);
162 } catch(NumberFormatException e) {}
164 return(null); /* XXX? */
166 addr = environ.get("X_ASH_SERVER_ADDRESS");
168 return(new InetSocketAddress(port)); /* XXX? */
170 return(new InetSocketAddress(addr, port));
173 public SocketAddress remoteaddr() {
176 addr = environ.get("REMOTE_ADDR");
177 portnum = environ.get("X_ASH_PORT");
181 port = Integer.parseInt(portnum);
182 } catch(NumberFormatException e) {}
183 if((addr != null) && (port >= 0))
184 return(new InetSocketAddress(addr, port));
185 return(null); /* XXX? */
188 private void checkstring(String s) {
189 for(int i = 0; i < s.length(); i++) {
190 char c = s.charAt(i);
191 if((c < 32) || (c >= 128))
192 throw(new RuntimeException("Invalid header string: " + s));
196 protected void backflush() throws IOException {
197 Writer out = new OutputStreamWriter(realoutput(), Misc.ascii);
198 out.write(String.format("Status: %d %s\n", respcode, resptext));
199 for(Map.Entry<String, String> e : outheaders().entrySet()) {
200 String k = e.getKey();
201 String v = e.getValue();
204 out.write(String.format("%s: %s\n", k, v));
210 protected OutputStream realoutput() {
212 return(sk.getOutputStream());
213 } catch(IOException e) {
214 /* It is not obvious why this would happen, so I'll wait
215 * until I know whatever might happen to try and implement
216 * meaningful behavior. */
217 throw(new RuntimeException(e));