001    /*
002     * LAPIS lightweight structured text processing system
003     *
004     * Copyright (C) 1998-2002 Carnegie Mellon University,
005     * Copyright (C) 2003 Massachusetts Institute of Technology.
006     * All rights reserved.
007     *
008     * This library is free software; you can redistribute it
009     * and/or modify it under the terms of the GNU General
010     * Public License as published by the Free Software
011     * Foundation, version 2.
012     *
013     * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014     */
015    
016    package lapisx.net;
017    
018    import java.net.*;
019    import java.io.*;
020    import java.util.*;
021    import lapisx.util.Exec;
022    import lapisx.util.Debug;
023    
024    public class LocalFormURL extends FormURL {
025        public static Debug debug = Debug.QUIET;
026    
027        /**
028         * Create a query using a given method (get or post) and query data.
029         * @param method "get" or "post" (case-insensitive).
030         * @param url URL to send query to.  Must be file:
031         * @param query Name/value pairs to simulate submitting a form.  Names and values may be arbitrary objects; this method uses toString() to convert them to strings, then URL-encodes them before sending to the web server.  Pass null if no form data is desired.  
032         */
033        public LocalFormURL (String method, URL url, Vector query) {
034            super (method, url, query);
035        }
036    
037        /**
038         * Open a URL using a given method (get or post) and query data.
039         * @param method "get" or "post" (case-insensitive). 
040         * @param url URL to open.  Must be file:
041         * @param query URL-encoded name/value pairs, or null if no query desired
042         */
043        public LocalFormURL (String method, URL url, String query) {
044            super (method, url, query);
045        }
046    
047        /**
048         * Open a connection ready to submit query and retrieve its results.
049         * @return URLConnection (set up for connection but not yet connected)
050         */
051        public URLConnection openConnection () throws IOException {
052            String protocol = url.getProtocol ();
053            if (!"file".equals (protocol))
054                throw new IOException ("local form URL must be file:"); 
055    
056            CGIConnection conn = new CGIConnection (method, url);
057    
058            // handle POST method
059            if ("post".equals (method)) {
060                conn.setDoOutput (true);
061                conn.setRequestProperty ("Content-type",
062                                         "application/x-www-form-urlencoded");
063                conn.setRequestProperty ("Content-length", String.valueOf (queryString.length()));
064                    
065                    // commence request
066                PrintWriter out = null;
067                try {
068                    out = new PrintWriter (new OutputStreamWriter
069                                           (conn.getOutputStream ()));
070                    out.print (queryString);
071                    out.flush ();
072                } finally {
073                    if (out != null)
074                        out.close ();
075                }
076            }
077    
078            conn.connect ();
079            return conn;
080        }
081    
082        static class CGIConnection extends URLConnection {
083            Process process;
084            String method;
085            String contentType = "text/plain";
086            long contentLength = 0;
087    
088            public CGIConnection (String method, URL url) {
089                super (url);
090                this.method = (method != null) ? method.toUpperCase () : "GET";
091            }
092    
093            public void setRequestProperty (String name, String value) {
094                if ("Content-type".equalsIgnoreCase (name))
095                    contentType = value;
096                else if ("Content-length".equalsIgnoreCase (name))
097                    contentLength = Long.valueOf (value).longValue ();
098            }
099     
100            public void connect () throws IOException {
101                if (connected) 
102                    return;
103    
104                URL serviceURL = URLUtil.getServiceURL (this.url);
105                String command = serviceURL.getFile ();
106                String query = URLUtil.getQuery (this.url);
107                if (query.startsWith ("?"))
108                    query = query.substring (1);
109    
110                String[] env = {
111                    "GATEWAY_INTERFACE=CGI/1.1",
112                    "SERVER_SOFTWARE=LAPIS",
113                    "SERVER_NAME=localhost",
114                    "SERVER_PORT=0",
115                    "REMOTE_ADDR=127.0.0.1",
116                    "REMOTE_HOST=localhost",
117                    "REQUEST_METHOD=" + method,
118                    "CONTENT_LENGTH=" + contentLength,
119                    "CONTENT_TYPE=" + contentType,
120                    "SCRIPT_NAME=" + command,
121                    "QUERY_STRING=" + query,
122                    "SERVER_PROTOCOL=HTTP/1.1",
123    //                 "PATH_INFO=",
124    //                 "PATH_TRANSLATED=",
125    //                 "REMOTE_USER=",
126    //                 "AUTH_TYPE="
127                };
128    
129                debug.println ("Connecting to " + this.url);
130                debug.println ("Executing local CGI script '" + command + "'");
131                debug.println (lapisx.util.Str.join (env, "\n"));
132    
133                process = Exec.exec (new String[] { command }, env);
134                connected = true;
135    
136                // Close output stream if unneeded (to keep subprocess from reading from it)
137                if (!doOutput)
138                    getOutputStream ().close ();
139            }
140    
141            public InputStream getInputStream () throws IOException {
142                connect ();
143                return process.getInputStream ();
144            }
145    
146            public OutputStream getOutputStream () throws IOException {
147                connect ();
148                return process.getOutputStream ();
149            }
150    
151        }
152    }