X-Git-Url: http://dolda2000.com/gitweb/?p=jsvc.git;a=blobdiff_plain;f=src%2Fdolda%2Fjsvc%2Fscgi%2FScgiRequest.java;fp=src%2Fdolda%2Fjsvc%2Fscgi%2FScgiRequest.java;h=192d3801029f1c3da1556502b35a3ddf3659d73e;hp=0000000000000000000000000000000000000000;hb=13e578b10b388cc0dea88e05b79265c21416e3a0;hpb=b560fc1c45ee31c6d509781b53d5934121990189 diff --git a/src/dolda/jsvc/scgi/ScgiRequest.java b/src/dolda/jsvc/scgi/ScgiRequest.java new file mode 100644 index 0000000..192d380 --- /dev/null +++ b/src/dolda/jsvc/scgi/ScgiRequest.java @@ -0,0 +1,217 @@ +package dolda.jsvc.scgi; + +import java.io.*; +import java.net.*; +import java.util.*; +import dolda.jsvc.*; +import dolda.jsvc.util.*; + +public class ScgiRequest extends ResponseBuffer { + final Socket sk; + private final Map environ; + private final InputStream in; + private final String method, path; + private final URL url, context; + private MultiMap params = null; + private MultiMap inhead = new HeaderTreeMap(); + + public ScgiRequest(Socket sk, Map environ) throws IOException { + this.sk = sk; + this.environ = environ; + for(Map.Entry var : environ.entrySet()) { + String k = var.getKey(); + if((k.length() > 5) && k.substring(0, 5).equals("HTTP_")) { + StringBuilder buf = new StringBuilder(); + boolean f = true; + for(int i = 5; i < k.length(); i++) { + char c = k.charAt(i); + if(c == '_') { + buf.append('-'); + f = true; + } else if(f) { + buf.append(Character.toUpperCase(c)); + f = false; + } else { + buf.append(Character.toLowerCase(c)); + } + } + inhead.add(buf.toString(), var.getValue()); + } + } + long len; + { + String h = environ.get("CONTENT_LENGTH"); + if(h == null) { + len = 0; + } else { + try { + len = Long.parseLong(h); + } catch(NumberFormatException e) { + throw(new InvalidRequestException("Invalid Content-Length header: " + h)); + } + } + } + this.in = new LimitInputStream(sk.getInputStream(), len); + path = environ.get("PATH_INFO"); + if(path == null) + throw(new InvalidRequestException("Missing PATH_INFO")); + method = environ.get("REQUEST_METHOD"); + if(method == null) + throw(new InvalidRequestException("Missing REQUEST_METHOD")); + { + /* Ewwww, this is disgusting! */ + String scheme = "http"; + if(environ.get("HTTPS") != null) + scheme = "https"; + int port = -1; + String host = environ.get("HTTP_HOST"); + if((host == null) || (host.length() < 1)) { + if((host = environ.get("SERVER_NAME")) == null) + throw(new InvalidRequestException("Both HTTP_HOST and SERVER name are missing")); + String portnum = environ.get("SERVER_PORT"); + if(portnum == null) + throw(new InvalidRequestException("Missing SERVER_PORT")); + try { + port = Integer.parseInt(portnum); + } catch(NumberFormatException e) { + throw(new InvalidRequestException("Bad SERVER_PORT: " + portnum)); + } + if((port == 80) && scheme.equals("http")) + port = -1; + else if((port == 443) && scheme.equals("https")) + port = -1; + } else { + int p; + if((host.charAt(0) == '[') && ((p = host.indexOf(']', 1)) > 1)) { + String newhost = host.substring(1, p); + if((p = host.indexOf(':', p + 1)) >= 0) { + try { + port = Integer.parseInt(host.substring(p + 1)); + } catch(NumberFormatException e) {} + } + host = newhost; + } else if((p = host.indexOf(':')) >= 0) { + try { + port = Integer.parseInt(host.substring(p + 1)); + host = host.substring(0, p); + } catch(NumberFormatException e) {} + } + } + String nm = environ.get("SCRIPT_NAME"); + if(nm == null) + throw(new InvalidRequestException("Missing SCRIPT_NAME")); + String q = environ.get("QUERY_STRING"); + if(q != null) + q = "?" + q; + else + q = ""; + try { + url = new URL(scheme, host, port, nm + path + q); + if(nm.charAt(nm.length() - 1) != '/') + nm += "/"; /* XXX? */ + context = new URL(scheme, host, port, nm); + } catch(MalformedURLException e) { + throw(new Error(e)); + } + } + } + + public MultiMap inheaders() { + return(inhead); + } + + public ServerContext ctx() { + return(ThreadContext.current().server()); + } + + public InputStream input() { + return(in); + } + + public URL url() { + return(url); + } + + public URL rooturl() { + return(context); + } + + public String path() { + return(path); + } + + public String method() { + return(method); + } + + public MultiMap params() { + if(params == null) + params = Params.stdparams(this); + return(params); + } + + public SocketAddress localaddr() { + String portnum = environ.get("SERVER_PORT"); + int port = -1; + try { + if(portnum != null) + port = Integer.parseInt(portnum); + } catch(NumberFormatException e) {} + if(port < 0) + return(null); /* XXX? */ + String addr; + addr = environ.get("X_ASH_SERVER_ADDRESS"); + if(addr == null) + return(new InetSocketAddress(port)); /* XXX? */ + else + return(new InetSocketAddress(addr, port)); + } + + public SocketAddress remoteaddr() { + String addr; + String portnum; + addr = environ.get("REMOTE_ADDR"); + portnum = environ.get("X_ASH_PORT"); + int port = -1; + try { + if(portnum != null) + port = Integer.parseInt(portnum); + } catch(NumberFormatException e) {} + if((addr != null) && (port >= 0)) + return(new InetSocketAddress(addr, port)); + return(null); /* XXX? */ + } + + private void checkstring(String s) { + for(int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if((c < 32) || (c >= 128)) + throw(new RuntimeException("Invalid header string: " + s)); + } + } + + protected void backflush() throws IOException { + Writer out = new OutputStreamWriter(realoutput(), Misc.ascii); + out.write(String.format("Status: %d %s\n", respcode, resptext)); + for(Map.Entry e : outheaders().entrySet()) { + String k = e.getKey(); + String v = e.getValue(); + checkstring(k); + checkstring(v); + out.write(String.format("%s: %s\n", k, v)); + } + out.write("\n"); + out.flush(); + } + + protected OutputStream realoutput() { + try { + return(sk.getOutputStream()); + } catch(IOException e) { + /* It is not obvious why this would happen, so I'll wait + * until I know whatever might happen to try and implement + * meaningful behavior. */ + throw(new RuntimeException(e)); + } + } +}