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"));
58 method = environ.get("REQUEST_METHOD");
60 throw(new InvalidRequestException("Missing REQUEST_METHOD"));
62 /* Ewwww, this is disgusting! */
63 String scheme = "http";
64 if(environ.get("HTTPS") != null)
67 String host = environ.get("HTTP_HOST");
68 if((host == null) || (host.length() < 1)) {
69 if((host = environ.get("SERVER_NAME")) == null)
70 throw(new InvalidRequestException("Both HTTP_HOST and SERVER name are missing"));
71 String portnum = environ.get("SERVER_PORT");
73 throw(new InvalidRequestException("Missing SERVER_PORT"));
75 port = Integer.parseInt(portnum);
76 } catch(NumberFormatException e) {
77 throw(new InvalidRequestException("Bad SERVER_PORT: " + portnum));
79 if((port == 80) && scheme.equals("http"))
81 else if((port == 443) && scheme.equals("https"))
85 if((host.charAt(0) == '[') && ((p = host.indexOf(']', 1)) > 1)) {
86 String newhost = host.substring(1, p);
87 if((p = host.indexOf(':', p + 1)) >= 0) {
89 port = Integer.parseInt(host.substring(p + 1));
90 } catch(NumberFormatException e) {}
93 } else if((p = host.indexOf(':')) >= 0) {
95 port = Integer.parseInt(host.substring(p + 1));
96 host = host.substring(0, p);
97 } catch(NumberFormatException e) {}
100 String nm = environ.get("SCRIPT_NAME");
102 throw(new InvalidRequestException("Missing SCRIPT_NAME"));
103 String q = environ.get("QUERY_STRING");
109 url = new URL(scheme, host, port, nm + path + q);
110 if(nm.charAt(nm.length() - 1) != '/')
111 nm += "/"; /* XXX? */
112 context = new URL(scheme, host, port, nm);
113 } catch(MalformedURLException e) {
119 public MultiMap<String, String> inheaders() {
123 public ServerContext ctx() {
124 return(ThreadContext.current().server());
127 public InputStream input() {
135 public URL rooturl() {
139 public String path() {
143 public String method() {
147 public MultiMap<String, String> params() {
149 params = Params.stdparams(this);
153 public SocketAddress localaddr() {
154 String portnum = environ.get("SERVER_PORT");
158 port = Integer.parseInt(portnum);
159 } catch(NumberFormatException e) {}
161 return(null); /* XXX? */
163 addr = environ.get("X_ASH_SERVER_ADDRESS");
165 return(new InetSocketAddress(port)); /* XXX? */
167 return(new InetSocketAddress(addr, port));
170 public SocketAddress remoteaddr() {
173 addr = environ.get("REMOTE_ADDR");
174 portnum = environ.get("X_ASH_PORT");
178 port = Integer.parseInt(portnum);
179 } catch(NumberFormatException e) {}
180 if((addr != null) && (port >= 0))
181 return(new InetSocketAddress(addr, port));
182 return(null); /* XXX? */
185 private void checkstring(String s) {
186 for(int i = 0; i < s.length(); i++) {
187 char c = s.charAt(i);
188 if((c < 32) || (c >= 128))
189 throw(new RuntimeException("Invalid header string: " + s));
193 protected void backflush() throws IOException {
194 Writer out = new OutputStreamWriter(realoutput(), Misc.ascii);
195 out.write(String.format("Status: %d %s\n", respcode, resptext));
196 for(Map.Entry<String, String> e : outheaders().entrySet()) {
197 String k = e.getKey();
198 String v = e.getValue();
201 out.write(String.format("%s: %s\n", k, v));
207 protected OutputStream realoutput() {
209 return(sk.getOutputStream());
210 } catch(IOException e) {
211 /* It is not obvious why this would happen, so I'll wait
212 * until I know whatever might happen to try and implement
213 * meaningful behavior. */
214 throw(new RuntimeException(e));